I open different files using a custom file number function that's mutexed.
I am opening the same files sometimes from different threads but all those files are always mutexed. but when opening different files in different threads im thinking there might be an issue with the OPEN / GET / PUT commands.
I'm using put / get and opening the file for random access. Do i need to be using mutexes with OPEN and GET and PUT# (File I/O) regardless of different files using those commands ??
I'm trying to hunt a down bug in my code and this came across my mind as a possible reason for a very very rare crash i need to find.
Thanks every one!
-SamL
is OPEN, Get and Put # (File I/O) thread safe?
Re: is OPEN, Get and Put # (File I/O) thread safe?
I cannot answer you categorically on the thread safe of such each keyword, but I advise you to use one common mutex for the full code block of access to files in any thread (including the main thread), if there is a possibility of conflict.
Example from the documentation so modified:
Example from the documentation so modified:
Code: Select all
Dim As Byte Ptr lpBuffer
Dim As Integer hFile, Counter, Size
Size = 256
lpBuffer = Allocate(Size)
For Counter = 0 To Size-1
lpBuffer[Counter] = (Counter And &HFF)
Next
Mutexlock(pMutex) '' <===
' Get free file file number
hFile = FreeFile()
' Open the file "test.bin" in binary writing mode
Open "test.bin" For Binary Access Write As #hFile
' Write 256 bytes from the memory pointed to by lpBuffer
Put #hFile, , lpBuffer[0], Size
' Close the file
Close #hFile
Mutexunlock(pMutex) '' <===
' Free the allocated memory
Deallocate lpBuffer
Re: is OPEN, Get and Put # (File I/O) thread safe?
ok, thanks for the help!
My testing of multi-thread with OPEN, GET and PUT resulted in no issues with multi-threading.
The very very rare crash I was hunting down turned out to be Windows 10 resetting the computer for updates and this caused some files to have unexpected data written to them.
Apparently Windows 10 home has no way to disable updates from restarting the computer with out applying unreliable hacks. So ill have to get windows 10 professional to fix this 'bug'.
Thanks again!
-SamL
My testing of multi-thread with OPEN, GET and PUT resulted in no issues with multi-threading.
The very very rare crash I was hunting down turned out to be Windows 10 resetting the computer for updates and this caused some files to have unexpected data written to them.
Apparently Windows 10 home has no way to disable updates from restarting the computer with out applying unreliable hacks. So ill have to get windows 10 professional to fix this 'bug'.
Thanks again!
-SamL
Re: is OPEN, Get and Put # (File I/O) thread safe?
For my personal information, did you put any mutex somewhere in relation to Freefile, Open / Close, Put / Get?
Re: is OPEN, Get and Put # (File I/O) thread safe?
I only mutexlock for the file number , and Im not using freefile()
Here is the code I used to test. ( I updated the code as I found a few mistakes.. )
NOTE: there is updated code for this test below that uses random strings for testing that will detect issues faster/better than this test.
Here is the code I used to test. ( I updated the code as I found a few mistakes.. )
NOTE: there is updated code for this test below that uses random strings for testing that will detect issues faster/better than this test.
Code: Select all
'press ESC key to stop test
dim shared as string file_name
file_name = "D:\test\"
Type Check_file_Entry ' used for check file in array_function_dba_checks.bi
sdata As String * 50
End Type
dim shared as ubyte freefile_numbers(1 to 255)
dim shared as string*100 freefile_owner(1 to 255)
for i as long = 1 to 255
freefile_owner(i) = "NONE"
next i
namespace mutex
dim as any ptr file_number
end namespace
mutex.file_number = mutexcreate
dim shared as byte Threads_go_now = 0
dim shared as byte threads_can_run = 1
function file_number( parameter as integer = 0 , ff_owner as string = "NONE" ) as integer
MutexLock mutex.file_number
dim as integer return_ff = 0
if parameter = 0 then 'get a number
for i as integer = lbound(freefile_numbers) to ubound(freefile_numbers)
if freefile_numbers(i) = 0 then
freefile_numbers(i) = 1
freefile_owner(i) = ff_owner
return_ff = i
exit for
end if
next i
else 'parameter = some file number, so time to release/reset the freefile number
freefile_numbers(parameter) = 0
freefile_owner(parameter) = "NONE"
return_ff = 0
end if
MutexUnLock mutex.file_number
return return_ff
end function
function new_FF(ff_owner as string) as integer
dim as integer FF = 0
while FF = 0
FF = file_number(,ff_owner)
if FF = 0 then
sleep 10,1
end if
wend
return FF
end function
Sub thread_write( ByVal userdata As Any Ptr )
Dim As Integer id = CInt(userdata)
print "STARTING THREAD #" & str(id)
dim checking_entry as Check_file_Entry
dim as string file = file_name & str(id) & ".txt"
dim as string file_entry
dim as integer ff
while Threads_go_now = 0
sleep id ' this will help allow threads to be un synced and this is what is needed for this test
wend
print "GO " & id
while THREADS_CAN_RUN = 1
ff = new_FF(__function__)
if open ( file For Random As #ff len=sizeof(Check_file_Entry)) = 0 then
for i as integer = 1 to 6
checking_entry.sdata = "test_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_" & str(id) : put #ff, i, checking_entry
next i
close #ff
else
end if
file_number( ff )
ff = new_FF(__function__)
if open (file For Random As #ff len=sizeof(Check_file_Entry)) = 0 then
for i as integer = 1 to 6
get #ff, i, checking_entry
if checking_entry.sdata <> "test_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_" & str(id) then print "ERROR"
next i
close #ff
else
end if
file_number( ff )
sleep 1
wend
print "STOP " & id
end sub
dim as any ptr thread_handles(1 to 255)
for i as integer = 1 to 255
thread_handles(i) = ThreadCreate(@thread_write, CPtr(Any Ptr, i))
next i
sleep 1000
Threads_go_now = 1
while inkey <> chr(27)
sleep 100
wend
print "Ending.."
threads_can_run = 0
For i As Integer = 1 To 255
If thread_handles(i) <> 0 Then
ThreadWait(thread_handles(i))
End If
Next
mutexdestroy mutex.file_number
print "done"
sleep
Last edited by SamL on Jul 17, 2020 17:36, edited 1 time in total.
Re: is OPEN, Get and Put # (File I/O) thread safe?
I learned that using freefile() only works in one thread at a time unless put a mutexlock around freefile() and OPEN.
freefile() checks how many files are open before returning a value. so there is a window of time that freefile() could return the same number if making multiple requests for a file number like in multi threading.
So that's why I'm not using freefile() for multithreading.
I suppose a way to use freefile() while multi threading is
freefile() checks how many files are open before returning a value. so there is a window of time that freefile() could return the same number if making multiple requests for a file number like in multi threading.
So that's why I'm not using freefile() for multithreading.
I suppose a way to use freefile() while multi threading is
Code: Select all
MutextLock free_file
ff = freefile
if open(file, #ff ) = 0 then
get / put #ff
close #ff
MutexUnLock free_file
else
MutexUnLock free_file
endif
Last edited by SamL on Jul 17, 2020 16:55, edited 4 times in total.
Re: is OPEN, Get and Put # (File I/O) thread safe?
Thanks.
By the way, look at this paragraph (#10) of 'Programmer's Guide' / 'Multi-Threading' / 'Critical Sections FAQ' I wrote:
10. Is it better to take precautions when using the keyword 'Sleep' in threads?
By the way, look at this paragraph (#10) of 'Programmer's Guide' / 'Multi-Threading' / 'Critical Sections FAQ' I wrote:
10. Is it better to take precautions when using the keyword 'Sleep' in threads?
- I was thinking in particular of the 2 Sleep in Sub thread_write():
- sleep id, 1
and
sleep 1, 1
to try against your crash ?
- sleep id, 1
Last edited by fxm on Jul 17, 2020 16:55, edited 2 times in total.
Re: is OPEN, Get and Put # (File I/O) thread safe?
ya i did not use sleep x,1 in this test.
I learned this recently that I needed to set all sleeps in threads to sleep x,1 when I started using fbgfx and screenevent while multi threading!
Thanks for the link that clarifies what I was reading in the forums concerning the needed sleep in threads.
I'm saving a link and will be reading the guide.
I learned this recently that I needed to set all sleeps in threads to sleep x,1 when I started using fbgfx and screenevent while multi threading!
Thanks for the link that clarifies what I was reading in the forums concerning the needed sleep in threads.
I'm saving a link and will be reading the guide.
Re: is OPEN, Get and Put # (File I/O) thread safe?
I edited the test code so it generates random strings for each thread so it should make the test better.
-SamL
Code: Select all
'press ESC key to stop test
dim shared as string file_name
file_name = "D:\test\"
Function rnd_range (first As Double, last As Double) As Double
Function = Rnd * (last - first) + first
End Function
Type Check_file_Entry ' used for check file in array_function_dba_checks.bi
sdata As String * 50
End Type
dim shared as ubyte freefile_numbers(1 to 255)
dim shared as string*100 freefile_owner(1 to 255)
for i as long = 1 to 255
freefile_owner(i) = "NONE"
next i
namespace mutex
dim as any ptr file_number
end namespace
mutex.file_number = mutexcreate
dim shared as byte Threads_go_now = 0
dim shared as byte threads_can_run = 1
function file_number( parameter as integer = 0 , ff_owner as string = "NONE" ) as integer
MutexLock mutex.file_number
dim as integer return_ff = 0
if parameter = 0 then 'get a number
for i as integer = lbound(freefile_numbers) to ubound(freefile_numbers)
if freefile_numbers(i) = 0 then
freefile_numbers(i) = 1
freefile_owner(i) = ff_owner
return_ff = i
exit for
end if
next i
else 'parameter = some file number, so time to release/reset the freefile number
freefile_numbers(parameter) = 0
freefile_owner(parameter) = "NONE"
return_ff = 0
end if
MutexUnLock mutex.file_number
return return_ff
end function
function new_FF(ff_owner as string) as integer
dim as integer FF = 0
while FF = 0
FF = file_number(,ff_owner)
if FF = 0 then
sleep 10,1
end if
wend
return FF
end function
Sub thread_write( ByVal userdata As Any Ptr )
Dim As Integer id = CInt(userdata)
print "STARTING THREAD #" & str(id)
dim checking_entry as Check_file_Entry
dim as string file = file_name & str(id) & ".txt"
dim as integer ff
dim as string file_code
for i as integer = 1 to 47
randomize
file_code += chr(rnd_range(33,126))
next i
while Threads_go_now = 0
sleep id,1 ' this will help allow threads to be un synced and this is what is needed for this test
wend
print "GO " & id
while THREADS_CAN_RUN = 1
ff = new_FF(__function__)
if open ( file For Random As #ff len=sizeof(Check_file_Entry)) = 0 then
for i as integer = 1 to 6
checking_entry.sdata = file_code & str(id) : put #ff, i, checking_entry
next i
close #ff
else
end if
file_number( ff )
ff = new_FF(__function__)
if open (file For Random As #ff len=sizeof(Check_file_Entry)) = 0 then
for i as integer = 1 to 6
get #ff, i, checking_entry
if checking_entry.sdata <> file_code & str(id) then print "ERROR"
next i
close #ff
else
end if
file_number( ff )
sleep 1,1
wend
print "STOP " & id
end sub
dim as any ptr thread_handles(1 to 255)
for i as integer = 1 to 255
thread_handles(i) = ThreadCreate(@thread_write, CPtr(Any Ptr, i))
next i
sleep 1000
Threads_go_now = 1
while inkey <> chr(27)
sleep 100
wend
print "Ending.."
threads_can_run = 0
For i As Integer = 1 To 255
If thread_handles(i) <> 0 Then
ThreadWait(thread_handles(i))
End If
Next
mutexdestroy mutex.file_number
print "done"
sleep