Freak is right.
In recent software (and new versions of my old) I've begun to instead signal
a thread to die gracefully.
One way to do this is to make a single instance thread, the easiest type of thread.
Like a audio thread, or graphics thread, or download thread, or simple file processing thread. Use a static variable in the procedure.
These threads either exist during the whole run of the program, or are used then removed. There are never two of the same type of thread.
Another is the multiple instance threads.
These are threads that do exactly the same but multiple times,
like two different file processing threads, or parallel calculations,
server instances etc.
Usually the number of threads are balanced to a multiple of the number of cores and so on.
Below are two implementations on how to gracefully make a single instance or multiple instance thread properly quit.
The single instance thread is only useful for that specific purpose, trying to use that for multiple threads will cause race conditions, and impossible to locate bugs due to multiple threads messing with the static running variable.
The multiple instance is a tad more complex but not much, and it can obviously be used for single instance threads as well and have the added benefit of being able to pass more flags/states in the thread structure which is very cool.
The code can probably be improved further by making some nice macros to simplify some of the creation and quitting of the multiple instance example.
Code: Select all
EnableExplicit
;Example 1:
Procedure.i ThreadSingleInstance_proc(start.i=#True)
Static running.i=#False
If start
If Not running
running=#True
While running
;The thread loop
Delay(1)
Wend
;clean stuff up, and let the proceduee/thread end naturally,
;PB should clean up allocations nicely this way too.
Debug "ending single"
Else
;We are allready running, ignoring.
EndIf
Else
running=#False
EndIf
EndProcedure
;Start the thread:
If CreateThread(@ThreadSingleInstance_proc(),#True)
;Let's do some other stuff here.
Delay(1000) ;Hey, I'm too lazy to do anything fancy here.
;End the thread:
ThreadSingleInstance_proc(#False)
EndIf
;-------------------------------------------------------------------
;Example 2:
Structure ThreadMultipleInstance_struct
running.i
;You can add further state vars here for the thread if you need them.
;Just make sure you avoid race conflicts though.
;What to put here? Well, a mutex var would be great here for example or something else, like a pause var for when the program is minimized etc.
EndStructure
Procedure.i ThreadMultipleInstance_proc(*thread.ThreadMultipleInstance_struct)
If *thread
If Not *thread\running
*thread\running=#True
While *thread\running
;The thread loop
Delay(1)
Wend
;clean stuff up, and let the proceduee/thread end naturally,
;PB should clean up allocations nicely this way too.
;You could even free the structure memory "here" by doing FreeMemory(*thread)
Debug "ending multi"
Else
;We are allready running, ignoring.
EndIf
Else
;thread structure pointer was 0 for some odd reason, ignore.
EndIf
EndProcedure
;Start the thread:
Define *thread1.ThreadMultipleInstance_struct
*thread1=AllocateMemory(SizeOf(ThreadMultipleInstance_struct)) ;Some of this stuff could probably be put in a macro or creation procedure.
If *thread1
If CreateThread(@ThreadMultipleInstance_proc(),*thread1)
;Let's do some other stuff here.
Delay(1000) ;Hey, I'm too lazy to do anything fancy here.
EndIf
;End the thread:
*thread1\running=#False
Delay(100) ;To make sure the thread manages to read it before we free it.
FreeMemory(*thread1) ;To avoid a racing issue here you might want to free the structure in the thread itself instead.
EndIf
Delay(1000) ;give stuff time to end above.