Thread Parameters?

Just starting out? Need help? Post your questions and find answers here.
Maya

Thread Parameters?

Post by Maya »

Hi,
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)
User avatar
mk-soft
Always Here
Always Here
Posts: 6320
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Thread Parameters?

Post by mk-soft »

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)
More over threads see https://www.purebasic.fr/english/viewtopic.php?t=73231
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Maya

Re: Thread Parameters?

Post by Maya »

Thank you mk-soft, however I'm still have a problem when applying your code.
Let's say we need to convert the following simpl Message box procedure into Thread:

Code: Select all

ProcedureDLL Msg (Title.s, Num1.i, Num2.i)
  MessageRequester (Title, Str(Num1 + Num2))
EndProcedure

  Msg ("Welcome", 100, 100)
To:

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)
The result error appears as follows:
Image

Any help will be much appreciated.
User avatar
Demivec
Addict
Addict
Posts: 4281
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: Thread Parameters?

Post by Demivec »

Maya wrote: Wed Apr 17, 2024 8:22 pm Thank you mk-soft, however I'm still have a problem when applying your code.
The result error appears as follows:
Image
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)
BarryG
Addict
Addict
Posts: 4219
Joined: Thu Apr 18, 2019 8:17 am

Re: Thread Parameters?

Post by BarryG »

A simpler alternative if speed isn't an issue:

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.
Last edited by BarryG on Thu Apr 18, 2024 10:10 pm, edited 1 time in total.
User avatar
STARGÅTE
Addict
Addict
Posts: 2260
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: Thread Parameters?

Post by STARGÅTE »

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.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
User avatar
mk-soft
Always Here
Always Here
Posts: 6320
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Thread Parameters?

Post by mk-soft »

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.
Thank you for mentioning them.
Sometimes I assume that this is known
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
BarryG
Addict
Addict
Posts: 4219
Joined: Thu Apr 18, 2019 8:17 am

Re: Thread Parameters?

Post by BarryG »

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.
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.
User avatar
mk-soft
Always Here
Always Here
Posts: 6320
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Thread Parameters?

Post by mk-soft »

It is always better to take a structure and create it for the entire runtime of the thread with AllocateStructure.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
STARGÅTE
Addict
Addict
Posts: 2260
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: Thread Parameters?

Post by STARGÅTE »

BarryG wrote: Thu Apr 18, 2024 10:09 pm
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.
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.
It's good that you're aware of this. However, such solution with Delay and the hope PeekS() has enough time is not optimal.
The use of a Semaphore would be more elegant and safe:

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)
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
BarryG
Addict
Addict
Posts: 4219
Joined: Thu Apr 18, 2019 8:17 am

Re: Thread Parameters?

Post by BarryG »

@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.

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)
User avatar
NicTheQuick
Addict
Addict
Posts: 1527
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Thread Parameters?

Post by NicTheQuick »

I once wrote this: https://www.purebasic.fr/english/viewto ... 39#p592739

And now I updated the code a bit to also include multiple parameters. Maybe that's interesting for you:

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))
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
User avatar
STARGÅTE
Addict
Addict
Posts: 2260
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: Thread Parameters?

Post by STARGÅTE »

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.
Semaphores guarantee that the thread has read the passed data completely.
A delay pauses the main program either to long or to short, not practicable.
So yes, I would recommend to switch to Semaphore.

Actually, the semaphore is used here not for the individual threads, it is used for the shared string parameter which you use. Therefore one semaphore is enough when you want to protect one variable.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
User avatar
skywalk
Addict
Addict
Posts: 4242
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Thread Parameters?

Post by skywalk »

Yes, semaphores have been very reliable for me.
Just be careful with the shared use of Map() data.
This is my NOTE TO SELF:
; Current PB Design means a Map()'s current element pointer is NOT "threaded".
; A read in one thread can change the current element within another thread.
; Unlike a shared Array() where each thread can browse different indices,
; if a current map element changes, then another thread will be tricked with its request for next map element.
; FEATURE REQUEST: Allow Map() read access from multiple threads.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
BarryG
Addict
Addict
Posts: 4219
Joined: Thu Apr 18, 2019 8:17 am

Re: Thread Parameters?

Post by BarryG »

The Semaphore approach isn't going to work for me, because "Global Semaphore.i = CreateSemaphore()" is global and my threads are going to be called more than once, so a global semaphore for a thread is going to send the signal to the wrong thread callers, right?
Post Reply