Just a question, is there a way to use more than one parameter in the "CreateThread" function?
Something like:
Code: Select all
CreateThread(@Thread(), Parm1, Parm2, Parm3)Code: Select all
CreateThread(@Thread(), Parm1, Parm2, Parm3)Code: Select all
Structure udtParameters
Parm1.i
Parm2.i
Parm3.i
EndStructure
Global myParams.udtParameters
myParams\Parm1 = 1
myParams\Parm2 = 3
myParams\Parm3 = 5
Procedure Thread(*myParams.udtParameters)
Protected a
a = *myParams\Parm1
Debug a
EndProcedure
CreateThread(@Thread(), @myParams)
Delay(1000)
Code: Select all
ProcedureDLL Msg (Title.s, Num1.i, Num2.i)
MessageRequester (Title, Str(Num1 + Num2))
EndProcedure
Msg ("Welcome", 100, 100)Code: Select all
ProcedureDLL Thread (*myParams.Parameters)
MessageRequester ("Title", Str(Num1+Num2))
EndProcedure
Structure Parameters
Title.s
Num1.i
Num2.i
EndStructure
Global myParams.Parameters
myParams\Title = "Title"
myParams\Num1 = 100
myParams\Num2 = 200
CreateThread (@Thread(), @myParams)
Delay(2500)
Maya wrote: Wed Apr 17, 2024 8:22 pm Thank you mk-soft, however I'm still have a problem when applying your code.
You need to place the structure definition before the thread procedure and to also reference the Parameters (in the structure that was passed as a pointer) like so:
Code: Select all
Structure Parameters
Title.s
Num1.i
Num2.i
EndStructure
ProcedureDLL Thread (*myParams.Parameters)
MessageRequester ((*myParams\Title, Str((*myParams\Num1+(*myParams\Num2))
EndProcedure
Global myParams.Parameters
myParams\Title = "Title"
myParams\Num1 = 100
myParams\Num2 = 200
CreateThread (@Thread(), @myParams)
Delay(2500)Code: Select all
; Enable thread safety in Compiler Options!
Procedure MyThread(params)
text$=PeekS(params)
n=CountString(text$,",")+1
For i=1 To n
p$=StringField(text$,i,",")
If p$
Debug p$
EndIf
Next
EndProcedure
text$="1,2,3,4,5" ; Five comma-separated params.
CreateThread(@MyThread(),@text$)
Delay(100) ; So PeekS() in MyThread() has time to copy the params.
Thank you for mentioning them.STARGÅTE wrote: Thu Apr 18, 2024 6:15 am At this point I would like to give an important note for both proposed solutions.
In both cases the information is passed just as a reference to the thread, and not as a variable or copy.
This means, the myParams.Parameters (first example) or text$ (second example) have to keep as they are as long as the thread is executed.
That's why my example has "text$=PeekS(params)" as the first line of the thread: to create a local copy of the params so they're not lost. Sometimes you'll need a small delay after creating the thread (100ms works great) so that PeekS() has time to copy the data. Edited my other post to show this.STARGÅTE wrote: Thu Apr 18, 2024 6:15 amIn both cases the information is passed just as a reference to the thread, and not as a variable or copy.
It's good that you're aware of this. However, such solution with Delay and the hope PeekS() has enough time is not optimal.BarryG wrote: Thu Apr 18, 2024 10:09 pmThat's why my example has "text$=PeekS(params)" as the first line of the thread: to create a local copy of the params so they're not lost. Sometimes you'll need a small delay after creating the thread (100ms works great) so that PeekS() has time to copy the data. Edited my other post to show this.STARGÅTE wrote: Thu Apr 18, 2024 6:15 amIn both cases the information is passed just as a reference to the thread, and not as a variable or copy.
Code: Select all
; Enable thread safety in Compiler Options!
Global Semaphore.i = CreateSemaphore()
Procedure MyThread(params)
text$=PeekS(params)
SignalSemaphore(Semaphore)
n=CountString(text$,",")+1
For i=1 To n
p$=StringField(text$,i,",")
If p$
Debug p$
EndIf
Next
EndProcedure
text$="1,2,3,4,5" ; Five comma-separated params.
CreateThread(@MyThread(),@text$)
WaitSemaphore(Semaphore)
text$="11,12,13,14,15" ; Five comma-separated params.
CreateThread(@MyThread(),@text$)
WaitSemaphore(Semaphore)
Delay(100)
Code: Select all
; Enable thread safety in Compiler Options!
Global Semaphore.i = CreateSemaphore()
Procedure MyThread_One(params)
text$=PeekS(params)
SignalSemaphore(Semaphore)
n=CountString(text$,",")+1
For i=1 To n
p$=StringField(text$,i,",")
If p$
Debug p$
EndIf
Next
EndProcedure
Procedure MyThread_Two(params)
text$=PeekS(params)
SignalSemaphore(Semaphore)
n=CountString(text$,",")+1
For i=1 To n
p$=StringField(text$,i,",")
If p$
Debug p$
EndIf
Next
EndProcedure
text$="1,2,3,4,5" ; Five comma-separated params.
CreateThread(@MyThread_One(),@text$)
WaitSemaphore(Semaphore)
text$="11,12,13,14,15" ; Five comma-separated params.
CreateThread(@MyThread_Two(),@text$)
WaitSemaphore(Semaphore)
Delay(100)

Code: Select all
EnableExplicit
Prototype.i ThreadProc(parameter.i)
Structure ThreadInfo
threadid.i
mutex.i
threadproc.ThreadProc
returnValue.i
EndStructure
Procedure WrapperThread(*threadInfo.ThreadInfo)
With *threadInfo
LockMutex(\mutex)
\returnValue = \threadproc(*threadInfo)
UnlockMutex(\mutex)
EndWith
EndProcedure
Procedure.i JoinThread(*threadInfo.ThreadInfo)
Protected returnValue.i
With *threadInfo
WaitThread(\threadid)
returnValue = \returnValue
FreeMutex(\mutex)
FreeStructure(*threadInfo)
EndWith
ProcedureReturn returnValue
EndProcedure
Procedure.i CreateThreadEx_(*threadProc, *threadInfo.ThreadInfo)
If Not *threadInfo
ProcedureReturn #False
EndIf
With *threadInfo
\threadproc = *threadProc
\mutex = CreateMutex()
\threadid = 0
LockMutex(\mutex)
EndWith
ProcedureReturn *threadInfo
EndProcedure
Macro CreateThreadEx(threadProc, structureName)
CreateThreadEx_(threadProc, AllocateStructure(structureName))
EndMacro
Procedure StartThread(*threadInfo.ThreadInfo)
With *threadInfo
If Not \threadid
\threadid = CreateThread(@WrapperThread(), *threadInfo)
UnlockMutex(\mutex)
EndIf
EndWith
EndProcedure
; ========================
; Here begins your program
; ========================
; Define your custom structure with all the parameters your thread needs
Structure mythread Extends ThreadInfo
parameter1.i
parameter2.i
parameter3.s
EndStructure
; Define your cthread
Procedure mythread(*mythread.mythread)
Protected sum.i, i.i, j.i
With *mythread
; Do something silly
For i = 1 To \parameter1
For j = 1 To \parameter2
sum + j
Debug \parameter3 + " sum: " + sum
; Make it run slower
Delay(50)
Next
Next
EndWith
; Return sum
ProcedureReturn sum
EndProcedure
; Create the thread and define its parameters
Debug "Define thread"
Define *thread1.mythread = CreateThreadEx(@mythread(), mythread)
*thread1\parameter1 = 10
*thread1\parameter2 = 2
*thread1\parameter3 = "Test"
Debug "Start thread"
StartThread(*thread1)
Debug "New threadid: " + *thread1\threadid
Debug "Join thread and get its return value"
Debug "Sum: " + Str(JoinThread(*thread1))
Semaphores guarantee that the thread has read the passed data completely.BarryG wrote: Fri Apr 19, 2024 11:18 am @STARGÅTE: Thanks for showing that. I should switch my Delays() to Semaphores() then for my threads? But, can I just use the one semaphore for all my different threads, or does each thread need its own dedicated semaphore?
What I mean is, is doing it like this safe? It appears to be.