Threading questions/problems
Re: Threading questions/problems
I think that is the same problem (due to ThreadCall):
The pointer value representing the address of 'I' is not preserved until the thread is launched, so a wrong value is passed to the thread ('9' instead of '4239396' in the above example) and the program crashes when it tries to access it!
The ThreadCall problem is general for all types of parameters passed, even by reference!
KeyPgThreadCall ⇒ FxMwikki [Generalized the warning sentence about any type of passed parameter]
The pointer value representing the address of 'I' is not preserved until the thread is launched, so a wrong value is passed to the thread ('9' instead of '4239396' in the above example) and the program crashes when it tries to access it!
The ThreadCall problem is general for all types of parameters passed, even by reference!
KeyPgThreadCall ⇒ FxMwikki [Generalized the warning sentence about any type of passed parameter]
Re: Threading questions/problems
dkl, would it be better that I also file a bug report (with a faults example for several passing types) even if you remember well that problem?
Re: Threading questions/problems
Yes, it'd be good to have a bug report for this.
Re: Threading questions/problems
Referring to ThreadCall documentation:
- unions
- user types containing unions, arrays, strings, or bitfields
but even if they are passed Byref !
For now, a workaround is to pass pointers Byval.
I am surprised that in fact (after trying) ThreadCall also refuses the subroutines with arguments like described above:.....
While most subroutines are supported, the following types of subroutines may not be called:
- Subroutines using variable arguments
- Subroutines with unions which are passed Byval
- Subroutines with user types containing unions, arrays, strings, or bitfields which are passed Byval
.....
- unions
- user types containing unions, arrays, strings, or bitfields
but even if they are passed Byref !
For now, a workaround is to pass pointers Byval.
Re: Threading questions/problems
My program cannot seem to communicate between the main sub and the threads. Here is some example code of the problem, the on screen numbers should be incrementing but are stuck at 1. Can anyone tell me what I am doing wrong and/or provide a simple fix? Please note that I do not like to work with pointers etc.
Thanks
Thanks
Code: Select all
screenres(800,600,32)
type list
waiting as integer
result as integer
end type
dim shared as integer threads=2
dim shared as integer thread_number
dim shared as any ptr thread_ptr(threads)
dim shared as list share(threads)
declare sub main
declare sub active_thread(none as any ptr)
main
sub main
dim as integer i,j,k
for i=1 to threads
sleep 100
thread_ptr(i)=threadcreate(@active_thread,0)
next i
print "press any key to exit"
do
sleep 1000
for i=1 to threads
if share(i).waiting=1 then share(i).waiting=0 'want to tell thread that it can start processing
print share(i).result,
next i
print
loop until inkey<>""
end sub
sub active_thread(none as any ptr)
thread_number+=1
dim as integer local_thread_number=thread_number
do
if share(local_thread_number).waiting=0 then 'start processing
sleep 900 'simulating calculations
share(local_thread_number).result+=1 'incrementing
share(local_thread_number).waiting=1 'want to tell sub main that thread is finished
end if
loop
end sub
Re: Threading questions/problems
Are you sure that is the above code which displays counters stuck at 1?
Even with a poor code like that, the counters should evolve more or less regularly.
Even with a poor code like that, the counters should evolve more or less regularly.
Re: Threading questions/problems
Why are you guys never reading DOC?
Example from DOC a little bit enhanced (readability):
Example from DOC a little bit enhanced (readability):
Code: Select all
'' Threading synchronization using Mutexes
'' If you comment out the lines containing "MutexLock" and "MutexUnlock",
'' the threads will not be in sync and some of the data may be printed
'' out of place.
Const MAX_THREADS = 10
Dim Shared As Any Ptr ttylock
'' Teletype unfurls some text across the screen at a given location
Sub teletype( ByRef text As String, ByVal x As Integer, ByVal y As Integer )
''
'' This MutexLock makes simultaneously running threads wait for each
'' other, so only one at a time can continue and print output.
'' Otherwise, their Locates would interfere, since there is only one
'' cursor.
''
'' It's impossible to predict the order in which threads will arrive
'' here and which one will be the first to acquire the lock thus
'' causing the rest to wait.
''
MutexLock ttylock
For i As Integer = 0 To (Len(text) - 1)
Locate x, y + i
Print Chr(text[i])
Sleep 25
Next
'' MutexUnlock releases the lock and lets other threads acquire it.
MutexUnlock ttylock
End Sub
Sub thread( ByVal userdata As Any Ptr )
Dim As Integer id = CInt(userdata)
teletype "Thread (" & id & ").........", 1 + id, 1
End Sub
' ===== MAIN =====
'' Create a mutex to syncronize the threads
ttylock = MutexCreate()
'' Create child threads
Dim As Any Ptr handles(0 To MAX_THREADS-1)
For i As Integer = 0 To MAX_THREADS-1
handles(i) = ThreadCreate(@thread, CPtr(Any Ptr, i))
If handles(i) = 0 Then
Print "Error creating thread:"; i
Exit For
End If
Next
'' This is the main thread. Now wait until all child threads have finished.
For i As Integer = 0 To MAX_THREADS-1
If handles(i) <> 0 Then
ThreadWait(handles(i))
End If
Next
'' Clean up when finished
MutexDestroy(ttylock)
' ===== END MAIN ===== ' ----- EOF -----
Re: Threading questions/problems
Better in my opinion, while keeping your poor principle of coding:
[edit]
- Added field "quit" for ending thread.
Code: Select all
screenres 800,600,32
type list
waiting as integer
result as integer
quit as integer
end type
dim shared as integer threads=2
dim shared as any ptr thread_ptr(1 to threads)
dim shared as list share(1 to threads)
declare sub main
declare sub active_thread(byval p as any ptr)
main
sub main
dim as integer i,j,k
for i=1 to threads
thread_ptr(i)=threadcreate(@active_thread,cptr(any ptr,i))
next i
print "press any key to exit"
do
sleep 1000
for i=1 to threads
if share(i).waiting=1 then 'testing if thread task is finished
print share(i).result;
share(i).waiting=0 'want to tell thread that it can start processing its task
end if
print ,
next i
print
loop until inkey<>""
for i=1 to threads
share(i).quit=1
Threadwait(thread_ptr(i))
next i
end sub
sub active_thread(byval p as any ptr)
dim as integer k=cint(p)
do
if share(k).waiting=0 then 'start processing task
sleep 900 'simulating calculations
share(k).result+=1 'incrementing
share(k).waiting=1 'want to tell sub main that thread task is finished
end if
sleep 100
loop until share(k).quit=1 'quit thread
end sub
- Added field "quit" for ending thread.
Re: Threading questions/problems
Thanks fxm,
Could not figure out why your example was working while mine wasn't. I found the problem but don't understand it. The following example now works, but does not work anymore after changing the line "loop until share(thread_number).quit=1" to "loop"?
Could not figure out why your example was working while mine wasn't. I found the problem but don't understand it. The following example now works, but does not work anymore after changing the line "loop until share(thread_number).quit=1" to "loop"?
Code: Select all
screenres(800,600,32)
type list
waiting as integer
result as integer
quit as integer
end type
dim shared as integer threads=2
dim shared as any ptr thread_ptr(1 to threads)
dim shared as list share(1 to threads)
declare sub main
declare sub active_thread(byval tn as any ptr)
main
sub main
dim as integer i
for i=1 to threads
thread_ptr(i)=threadcreate(@active_thread,cptr(any ptr,i))
next i
print "press any key to exit"
do
sleep 1000
for i=1 to threads
if share(i).waiting=1 then share(i).waiting=0 'want to tell thread that it can start processing
print share(i).result,
next i
print
loop until inkey<>""
for i=1 to threads
share(i).quit=1
threadwait(thread_ptr(i))
next i
end sub
sub active_thread(byval tn as any ptr)
dim as integer thread_number=cint(tn)
do
if share(thread_number).waiting=0 then 'start processing
sleep 900 'simulating calculations
share(thread_number).result+=1 'incrementing
share(thread_number).waiting=1 'want to tell sub main that thread is finished
end if
loop until share(thread_number).quit=1
end sub
Re: Threading questions/problems
No problem on my PC (double core) when using "loop until share(thread_number).quit=1", except obviously that the program blocks and does not exit when entering a character.
Perhaps add a very small sleep in the loop to prevent to hogging the CPU::
Perhaps add a very small sleep in the loop to prevent to hogging the CPU::
Code: Select all
sub active_thread(byval tn as any ptr)
dim as integer thread_number=cint(tn)
do
if share(thread_number).waiting=0 then 'start processing
sleep 900 'simulating calculations
share(thread_number).result+=1 'incrementing
share(thread_number).waiting=1 'want to tell sub main that thread is finished
end if
sleep 10
loop ''until share(thread_number).quit=1
end sub
Re: Threading questions/problems
Recoded code from Provoni, to improve readability as well as timing (calling thread-proc.).
Changed types used, and eliminated as many 'globals' (shared) as possible. Removed: Sub main.
Added a certain amount of 'style' to code (aka: first things first, etc.), also added comments:
Changed types used, and eliminated as many 'globals' (shared) as possible. Removed: Sub main.
Added a certain amount of 'style' to code (aka: first things first, etc.), also added comments:
Code: Select all
Declare Sub active_thread(ByVal p As Any Ptr) ' the 'p' is optional here
Type list
As Integer result
As Boolean waiting ' integer --> waste of memory!
As Boolean quit ' integer
End Type
Dim Shared As list share(Any) ' global, dynamic array (undefined at present)
' globals
Const threads = 2 ' type is: integer (infered from initializer)
ReDim Shared As list share(1 to threads) ' size dyn. array
' locals
Dim As Any Ptr thread_ptr(1 to threads)
Dim As UInteger i ',j,k --> never used anyway (UInteger is the faster loop-counter!)
'----- prog start -----
ScreenRes 800, 600, 32
Width , 600 \ 16
' start threads
For i = 1 To threads
thread_ptr(i) = ThreadCreate(@active_thread,CPtr(Any Ptr, i))
Next i
Print "press any key to exit"
' main-loop
Do
For i = 1 to threads
If share(i).waiting = TRUE Then 'testing if thread task is finished
Print share(i).result;
share(i).waiting = FALSE 'want to tell thread that it can start processing its task
End if
Print ,
Sleep 100 ' give it a break, before calling other thread!
Next i
Print
Sleep 900
Loop Until Len(InKey())
' stop threads
For i = 1 To threads
share(i).quit = TRUE
ThreadWait(thread_ptr(i))
Next i
' ----- prog end -----
' thread-proc.
Sub active_thread(ByVal p As Any Ptr)
Dim as integer k = cint(p)
Do
If share(k).waiting = FALSE Then'start processing task
Sleep 900 'simulating calculations
share(k).result += 1 'incrementing
share(k).waiting = TRUE 'want to tell main that thread task is finished
End If
Sleep 100
Loop Until share(k).quit = TRUE 'quit thread
End Sub
' ----- EOF -----
Re: Threading questions/problems
Just tested that it fails to increment with 1.05.0 win64 but not with 1.05.0 win32. On a quad core running Win7.fxm wrote:No problem on my PC (double core) when using "loopuntil share(thread_number).quit=1", except obviously that the program blocks and does not exit when entering a character.
This fixes the incrementing problem with 1.05.0 win64.fxm wrote:Perhaps add a very small sleep in the loop to prevent to hogging the CPU:
It did however not fix the issue for my main program, but just resolved that now by removing a small part of code in the main loop of the thread that used a mutex. The code inside the mutex has nothing to do with communication between the main sub and threads.
Thanks for your example and tips MrSwiss.
Re: Threading questions/problems
No problem for me both in 32bit and in 64bit with Win7, but with a CORE i5 processor (only double core).Provoni wrote:Just tested that it fails to increment with 1.05.0 win64 but not with 1.05.0 win32. On a quad core running Win7.fxm wrote:No problem on my PC (double core) when using "loopuntil share(thread_number).quit=1", except obviously that the program blocks and does not exit when entering a character.
Re: Threading questions/problems
I had some problems passing data to thread started by ThreadCreate() - if I quit calling function right after creating thread, data passed to this thread go bad. So question - is ThreadCreate() returning only after starting thread and safely passing data inside it, or before it?
Example - if i remove Sleep(88,1) in code below, thread receive garbled data:
To get around issue and not wait fixed amount of time, mutex should be better:
Or it just bug of ThreadCreate() ?
Example - if i remove Sleep(88,1) in code below, thread receive garbled data:
Code: Select all
Public Function UpdateTaskStart(iID As ULong, psMask As ZString Ptr, byref pwsParamA As WString Ptr, pwsParamB As WString Ptr, iParamC As ULong) As Long Export
' ----------------------------------------------------------------------------------------
'
' ----------------------------------------------------------------------------------------
Dim tData As tagUpdateTask Ptr = New tagUpdateTask(iID, psMask, pwsParamA, pwsParamB, iParamC)
' ..................................................................................
Dim As Any Ptr ThreadHandle = ThreadCreate(@Thread_UpdateTask, tData, iThreadStackSize)
If ThreadHandle = 0 Then
Print "UpdateTaskStart Thread : start / failed : ";tagUpdateTask->Name
Return 40400003
Else
Sleep(88,1) <---------------------- wait
ThreadDetach(ThreadHandle)
End If
' ----------------------------------------------------------------------------------------
Return 0
End Function
Code: Select all
Public Function UpdateTaskStart(iID As ULong, psMask As ZString Ptr, byref pwsParamA As WString Ptr, pwsParamB As WString Ptr, iParamC As ULong) As Long Export
' ----------------------------------------------------------------------------------------
'
' ----------------------------------------------------------------------------------------
Dim ptData As tagUpdateTask Ptr = New tagUpdateTask(iID, psMask, pwsParamA, pwsParamB, iParamC)
' ..................................................................................
MutexLock(GlobalThreadStartMutex)
' ..................................................................................
Dim As Any Ptr ThreadHandle = ThreadCreate(@Thread_UpdateTask, ptData, iThreadStackSize)
If ThreadHandle = 0 Then
MutexUnLock(GlobalThreadStartMutex)
Print "UpdateTaskStart Thread : start / failed : ";tagUpdateTask->Name
Return 40400003
Else
MutexLock(GlobalThreadStartMutex)
ThreadDetach(ThreadHandle)
MutexUnLock(GlobalThreadStartMutex)
End If
' ----------------------------------------------------------------------------------------
Return 0
End Function
Sub Thread_UpdateTask(ByVal userdata As Any Ptr)
'-----------------------------------------------------------------------------------------
Dim As tagUpdateTask Ptr ptData = CPtr(tagUpdateTask Ptr, userdata)
MutexUnLock(GlobalThreadStartMutex)
'-----------------------------------------------------------------------------------------
'
'-----------------------------------------------------------------------------------------
'
' calculations...
'
'-----------------------------------------------------------------------------------------
Delete ptData
'-----------------------------------------------------------------------------------------
End Sub