dim shared as boolean finished=false
dim shared as string string1, string2
string1="1" : string2="2"
sub stringChange()
do
string2="'"+chr(128+rnd*64)+"'"
swap string1, string2
loop until finished
end sub
screen 13
dim shared as any ptr stringChange_ptr=procptr(stringChange)
dim shared as any ptr stringChange_thread : stringChange_thread=threadcreate(stringChange_ptr,0)
do
locate 1,1 : print string1+" "
screensync()
flip()
loop until multikey(1)
finished=true
threadwait stringChange_thread
This code is a much simpler version of something I'm working on.
I have 2 shared strings.
The secondary thread will modify 'string2' and swap it with 'string1'.
The main thread will only read from 'string1'.
The strings are never erased. If I understand this correctly, both strings will stay in memory while the program is running, and they will only swap addresses.
My question is: does this code need a mutex?
It is safer to:
- Use a thread sub of signature: 'Sub(Byval As Any Ptr)'.
- Use a mutex to avoid multi-threading conflict between 'swap string1, string2' and 'print string1+" "', even if 'swap' only exchanges the string decriptors, because the descriptor structure corresponds to a Pointer + 2 Integers.
In your special case where the two strings have the same size (and are not reallocated), that may work, except for the starting (string size: 1 => 3).
I would not comment the use of 'screensync()' and 'flip()' !
fxm wrote:It is safer to:
- Use a thread sub of signature: 'Sub(Byval As Any Ptr)'.
- Use a mutex to avoid multi-threading conflict between 'swap string1, string2' and 'print string1+" "', even if 'swap' only exchanges the string decriptors, because the descriptor structure corresponds to a Pointer + 2 Integers.
In your special case where the two strings have the same size (and are not reallocated), that may work, except for the starting (string size: 1 => 3).
I would not comment the use of 'screensync()' and 'flip()' !
Thank you, fxm!
So, I may get into trouble if the strings change in size.
dim shared as boolean finished=false
dim shared as string string1, string2
string1="1" : string2="2"
dim shared as any ptr stringChange_mutex : stringChange_mutex=mutexcreate()
sub stringChange(Byval dummy As Any Ptr=0)
do
string2="'"+chr(128+rnd*64)+"'"
mutexlock stringChange_mutex
swap string1, string2
mutexunlock stringChange_mutex
loop until finished
end sub
screen 13
dim shared as any ptr stringChange_ptr=procptr(stringChange)
dim shared as any ptr stringChange_thread : stringChange_thread=threadcreate(stringChange_ptr,0)
do
locate 1,1
mutexlock stringChange_mutex
print string1+" "
mutexunlock stringChange_mutex
screensync()
flip()
loop until multikey(1)
finished=true
threadwait stringChange_thread
mutexdestroy(stringChange_mutex)
Anything wrong in using 'screensync' and 'flip', btw?
dim shared as any ptr stringChange_ptr=procptr(stringChange)
dim shared as any ptr stringChange_thread : stringChange_thread=threadcreate(stringChange_ptr,0)
dim shared as any ptr stringChange_thread : stringChange_thread=threadcreate(@stringChange)
'' or:
dim shared as any ptr stringChange_thread : stringChange_thread=threadcreate(procptr(stringChange))
Or if you absolutely want to define a procedure pointer: dim shared as sub(byval as any ptr) stringChange_ptr=procptr(stringChange)
dim shared as any ptr stringChange_thread : stringChange_thread=threadcreate(stringChange_ptr,0)
Why do you want to protect from possible flickering?
- The window is never cleared.
- Always the same number of characters are written starting from the same location (1, 1).
Otherwise:
- 'screensynch()' is a process of thumb because the plotting/printing must fit inside the small interval between the frames tracing ('screenlock' ... 'screenunlock' is preferable).
- 'flip()' requires the declaration and use of 2 screen pages (a working page and a displayed page).
fxm wrote:Why do you want to protect from possible flickering?
- The window is never cleared.
- Always the same number of characters are written starting from the same location (1, 1).
Otherwise:
- 'screensynch()' is a process of thumb because the plotting/printing must fit inside the small interval between the frames tracing ('screenlock' ... 'screenunlock' is preferable).
- 'flip()' requires the declaration and use of 2 screen pages (a working page and a displayed page).
Heh, it's just something I have put together quickly.
In my actual program I'm using OpenGL, so I always use the FLIP.
And I only use SCREENSYNC when I need to limit the frame rate, but I usually just enable VSYNC using the OpenGL extensions.
FB stores the length and content separately, so doing pretty much anything with a dynamic string requires at least two reads. And things that require multiple reads can be interrupted, so this can happen
string1 is 20 characters long
string 2 is 5 characters long
Thread 1
--- processes 'Print string1'
--- The FB internals read string1's length (20) and store it in a local variable
Thread 2 interrupts
--- the whole string swap is completed
--- string1 now has the 5 character data, and string 2 20
Thread 1 runs again
--- The FB internals now read string1's data of 5 characters... and then 15 more since it read a length of 20 before it was interrupted
--- Print completes
Now you have Hello@~@}{}:@;#;<>¬¬ on the screen, or a crash, instead of just Hello, or whatever was in string 1 when the Print started.
Even if swap only swaps the strings addresses rather than the full descriptors (I don't know which it does), the same thing applies.
'Print string1' copies the value of the current string1 pointer into Print to work with, since Print arguments are byval
the swap happens
your non-Print thread now happily modifies string2
- but string2 is the same pointer that may be still inside Print being read from, uh-oh
Type myData
Dim As String string1="1"
Dim As String string2="2"
Dim As Boolean finished=False
Dim As Any Ptr stringChange_thread
Dim As Any Ptr stringChange_mutex
End Type
Sub stringChange(Byval p As Any Ptr)
With *Cptr(myData Ptr, p)
Do
.string2="'"+Chr(128+Rnd*64)+"'"
Mutexlock(.stringChange_mutex)
Swap .string1, .string2
Mutexunlock(.stringChange_mutex)
Loop Until .finished
End With
End Sub
Screen 13
Dim As myData md
With md
.stringChange_mutex = Mutexcreate()
.stringChange_thread = Threadcreate(@stringChange, @md)
Do
Locate 1,1
Mutexlock(.stringChange_mutex)
Print .string1+" "
Mutexunlock(.stringChange_mutex)
Sleep 15, 1
Loop Until Multikey(1)
.finished = True
Threadwait(.stringChange_thread)
Mutexdestroy(.stringChange_mutex)
End With