Another option is using a Map of Structures with an integer converted to a string as the key.
I think it's best to add/delete map elements in the main thread, I find it's easier to keep track that way:
Code: Select all
EnableExplicit
Enumeration windows
#frmMain
EndEnumeration
Enumeration gadgets
#frmMain_btnThreads
EndEnumeration
Enumeration #PB_Event_FirstCustomValue
#EventThreadComplete
EndEnumeration
Structure AddIt
a.i
b.i
x.i
EndStructure
Global MapIndex.i
Global NewMap MyMap.AddIt()
Global Mutex = CreateMutex()
; work that happens in a thread
Procedure ThreadStuff(nMapId)
Define.i nA, nB, nX
; grab any incoming data we need for our work ...
LockMutex(Mutex)
If FindMapElement(MyMap(), Str(nMapId))
nA = MyMap()\a
nB = MyMap()\b
EndIf
UnlockMutex(Mutex)
; perform the intensive, time-consuming work ...
nX = nA + nB
; record the outcome ...
LockMutex(Mutex)
If FindMapElement(MyMap(), Str(nMapId))
MyMap()\x = nX
EndIf
UnlockMutex(Mutex)
; announce thread has completed its task ...
; the map id is attached to the event as its data ...
PostEvent(#EventThreadComplete, 0, 0, 0, nMapId)
EndProcedure
; PostEvent() handler is back in the main thread ...
Procedure onPostEvent()
; EventData() tells us which map element is broadcasting ...
Protected nIdx.i = EventData()
Protected sResult.s
LockMutex(Mutex)
If FindMapElement(MyMap(), Str(nIdx))
; read the result of the thread's work ...
sResult = Str(MyMap()\a) + " + " + Str(MyMap()\b) + " = " + Str(MyMap()\x)
Debug sResult
; we've handled this element so we can clean up ...
DeleteMapElement(MyMap(), Str(nIdx))
EndIf
UnlockMutex(Mutex)
EndProcedure
; gadget event handlers
Procedure onGadget()
Protected nGadget = EventGadget()
If nGadget = #frmMain_btnThreads
; launch a new task in a thread ...
MapIndex + 1
LockMutex(Mutex)
AddMapElement(MyMap(), Str(MapIndex))
MyMap()\a = Random(100, 0)
MyMap()\b = Random(100, 0)
UnlockMutex(Mutex)
CreateThread(@ThreadStuff(), MapIndex)
EndIf
EndProcedure
Procedure frmMain_Open()
If OpenWindow(#frmMain, 20, 20, 400, 300, "Threads Example")
ButtonGadget(#frmMain_btnThreads, 10, 10, 150, 30, "Test")
EndIf
EndProcedure
BindEvent(#PB_Event_Gadget, @onGadget())
BindEvent(#EventThreadComplete, @onPostEvent())
frmMain_Open()
Repeat
Define.i nEvent = WaitWindowEvent(50)
Until nEvent = #PB_Event_CloseWindow