BASIC design flaw. freefile
returns an unused file number which is not reserved, so if you open files on multiple threads another thread might intercede, call freefile
+open
and thus the open
on the other thread will fail, returning fberrILLEGAL_CALL.
FreeFile on the wiki mentions "it is wise to use Freefile immediately before its corresponding Open, to ensure that the file number is not returned and opened elsewhere first." But ensure here is false, it doesn't ensure it and if you want to avoid it you need either 1) do your own locking, 2) do your own allocation of file numbers, either statically or reimplementing or wrapping FreeFile, 3) call open
in a loop until it succeeds (but how do you distinguish from other errors?)
It would be nice if FreeFile were optional, Open took the file number byref and picked and returned it itself if you pass 0 (which is not a valid file number), which is both a simplification and a fix. (I have my own openfile
that does this and happily deleted hundreds of freefile calls.) This would either require an ABI change or an unpleasantly large number of new entry points... but 1.08 changes the ABI anyway.
Another solution might be to keep track of file numbers that have returned from FreeFile but not passed to Open yet, and make FreeFile not return one of these unless the available file numbers would otherwise be exhausted (so programs that don't have matched FreeFile/Open calls don't break). However this changes documented behaviour and can potentially break programs which use a mix of manual file number allocation and FreeFile.
Testcase:
dim shared as integer fh1, fh2 sub tryopen(arg as any ptr) dim byref fh as integer = *cast(integer ptr, arg) do fh = freefile if open("dummy.tmp" for binary as fh) then ? "open failed: fh1=" & fh1 & " fh2=" & fh2 system end if ? fh; close #fh loop end sub threadcreate @tryopen, @fh1 tryopen @fh2
Running it always soon ends with "open failed: fh1=1 fh2=1".
Another more rational solution, to resolve this conflict between threads and allocation of file numbers, is to define a mutual exclusion using a mutex blocking around the FreeFile...Open sequence:
Yes, I mentioned mutexes as a workaround for this problem. Wrapping every Open call is burdensome though. This isn't an implementation bug, it's a flaw in FB that would ideally be fixed.
In first time, I think it is useful to add this constraint in the 'Freefile' documentation page:
Last edit: fxm (freebasic.net) 2021-01-09