Yeh spotted some nasty bugs, firstly the PB debuger is the least thread safe debugger I know

no offence intended!
Best to take all the debug statements out. Second of all I spotted a nasty bug in my code which Ive corrected.
Ive changed the code to show a more graphical and human friendly output of the threads working.
Lastly try setting the number of tasks to a hundred and the pool size to a 100 and run without debugging you will almost certainly get a race condition (read/write memory lock) and crach the application. This is down to the lack of thread safety in the application and the underlying PureBasic code. Just be aware of it, you can hide this 'feature' by working on timings and possibly using some asm code to lock the strucutre byte when you read and set it.
Code: Select all
#TotalTasks = 100 ; total number of tasks to action
#ThreadPoolSize = 10 ; Max size of the thread pool so 6 slots for us here
#INUSE = 1
#EMPTY = 0
#PROGRESS_TIME = 350
Global TaskIndex.l
TaskIndex = 0 ; position of the last task executed
Structure ThreadInfo
ThreadInUse.b
ThreadID.l
ServerName.s
Number.l
ChangedName.s
TaskID.l
EndStructure
Dim ThreadPool.ThreadInfo(#ThreadPoolSize) ; tracks usage of my thread pool slot and data
Procedure DoTask(ThreadPoolSlotID.l)
RandomTaskTime.l = Random(400)+#PROGRESS_TIME
UniqueGadgetWindowID = ThreadPool(ThreadPoolSlotID)\TaskID + 1
OpenWindow(UniqueGadgetWindowID, 200+Random(400), 200+Random(400), 300, 100, #PB_Window_SystemMenu , "Thread No: "+Str(ThreadPoolSlotID)+" Task "+Str(ThreadPool(ThreadPoolSlotID)\TaskID))
CreateGadgetList(WindowID(UniqueGadgetWindowID))
ProgressBarGadget(UniqueGadgetWindowID, 10, 10, 280, 50, 0, RandomTaskTime, #PB_ProgressBar_Smooth)
exit = #False
Repeat
;UseWindow(ThreadPool(ThreadPoolSlotID)\TaskID)
eventid = WindowEvent()
If GetGadgetState(UniqueGadgetWindowID) < RandomTaskTime
SetGadgetState(UniqueGadgetWindowID, GetGadgetState(UniqueGadgetWindowID) + 1)
Else
CloseWindow(UniqueGadgetWindowID)
exit = #True
Break
EndIf
Delay(1)
Until exit = #True
; must be the very last thing we do before we exit
ThreadPool(ThreadPoolSlotID)\ThreadInUse = #EMPTY
EndProcedure
Procedure InitialiseThreadInfo(ThreadInfoID.l)
ThreadPool(ThreadInfoID)\ThreadInUse = #EMPTY ; 0 = empty not in use, non zero = in use
ThreadPool(ThreadInfoID)\ThreadID = 0 ; thread ID returned from starting thread (in case we need to kill it)
ThreadPool(ThreadInfoID)\ServerName = "" ; string to check our non thread safe data
ThreadPool(ThreadInfoID)\Number = 0 ; number to add spice to life
ThreadPool(ThreadInfoID)\ChangedName = "" ; another string in a different position!
ThreadPool(ThreadInfoID)\TaskID = 0
EndProcedure
Procedure InitialiseThreadPool()
; Clear our thread pool
For ClearThreadPoolID = 0 To #ThreadPoolSize
InitialiseThreadInfo(ClearThreadPoolID)
Next ClearThreadPoolID
EndProcedure
; Main Program
exit = #False
;Delay(1000)
Debug "****-> Start of main program"
; start from task 0
TaskIndex = 0
; initialise the thread pool for use
InitialiseThreadPool()
Repeat
For ThreadPoolID = 0 To #ThreadPoolSize ; check every slot in the thread pool for an openeing
If ThreadPool(ThreadPoolID)\ThreadInUse = #EMPTY ; empty slot so we can Start a task using this slot
If TaskIndex = #TotalTasks ; We've completed all the scheduled tasks skip out
exit = #True
Break
Else
; Clean out the junk from the last thread before we use the slot
InitialiseThreadInfo(ThreadPoolID)
; kick off the next thread task
ThreadPool(ThreadPoolID)\ThreadID = CreateThread(@DoTask(),ThreadPoolID)
; simple error checking to make sure we dont waste slots on threads that didnt start
If ThreadPool(ThreadPoolID)\ThreadID <> 0
; very first thing we do before anything else
ThreadPool(ThreadPoolID)\ThreadInUse = #INUSE ; reserve our slot and only the thread can unreserve its own slot
ThreadPool(ThreadPoolID)\TaskID = TaskIndex
; note no guarantee that the task will complete successfully just that we scheduled
; it and its running!
; finally if the thread contains a non zero value then increment
; the Number of tasks initiated
TaskIndex + 1
Else
; issue starting the thread for whatever reason
; clear the slot and it will be retried next time round
InitialiseThreadInfo(ThreadPoolID)
EndIf
EndIf
Else
; do nothing thread pool slot is busy
Delay(200)
EndIf
Next ThreadPoolID
Until exit = #True
Debug "****-> End of Main Program"
Hope this helps you and others...
IRIA