Page 1 of 1

Have threads got their own ressources?

Posted: Sat May 17, 2008 7:45 pm
by AND51
Hello!

I'm wondering, wether each thread has got it's own ressources or not.
This thinking appeares, when I create common procedures and I want to publish them in the PB-forums. The critical point is for example Static variables. Do they have different values although they're called by 2 or more different threads?

I think, they should have different values, but I couldn't watch this behaviour. Let's have a look at this code:

Code: Select all

Procedure expressionError(thread)
	CreateRegularExpression(#PB_Any, "(?") ; "unrecognized character after (?"
	Delay(4000) ; pretend being busy
	Debug RegularExpressionError() ; now we read the error msg (NOT threadsafe: it has been overwritten??)
EndProcedure

thread1=CreateThread(@expressionError(), 0)

Procedure readExpressionError(thread)
	CreateRegularExpression(#PB_Any, "*") ; "nothing to repeat"
	Delay(0)
	Debug RegularExpressionError() ; now we read the error msg
EndProcedure

thread2=CreateThread(@readExpressionError(), 0)

WaitThread(thread1)
WaitThread(thread2)
Compile it in 2 modes: Threadsafe and not threadsafe.

Both times, when CreateRegularExpression() is called, an error occurs. This error should be read with RegularExpressionError().
Debugoutput NOT threadsafe wrote:nothing to repeat
nothing to repeat
Debugoutput threadsafe wrote:nothing to repeat
unrecognized character after (?
The first one is incorrect, because the error is overwritten by the second thread. Or is it even a bug?
The second output is correct. Each thread can read it's own error message.

This leads me to the conclusion that each thread at least with threadsafe mode on has got it's own ressources.
Do you agree? Do I understand this phenomenon right?

Then let's have a look at the second code, regarding the 'critical point', e. g. variables using Static:

Code: Select all

Procedure commonUsed()
	Static expression
	If Not expression
		expression=CreateRegularExpression(#PB_Any, ".*")
		Debug "regExp has ben created"
	EndIf
EndProcedure


Procedure expressionError(thread)
	commonUsed()
	Delay(4000)
EndProcedure

thread1=CreateThread(@expressionError(), 0)

Procedure readExpressionError(thread)
	commonUsed()
	Delay(4000)
EndProcedure

thread2=CreateThread(@readExpressionError(), 0)

WaitThread(thread1)
WaitThread(thread2)
Compile this code with and without threadsafe, too. Well, what can we see? 2 threads are created, using the procedure commonUsed(). This procedre should create something, but only once. This ressource is for further+multiple use, thus it needs to be created only once.

What does the debugger say? It indicates that the 'object' is only being created once:

Code: Select all

regExp has ben created

Final Conclusion:
Well, is the conclusion from the first code incorrect? Do threads only have different ressources at PureBasic's wil or randomly? What's the general rule?
This leads me to the point where I avoid coding procedures with static variables that should be able to work correctly in ANY case: normal mode, threadsafe, unicode+threadsafe, ...

This behaviour can be a problem: Imagine each thread sends and receives data via network and calls a commonly used procedure. If this procedure then uses a static buffer, everything ends in a mess..

So let's have a nice discussion about this and I hope you can explain it to me. Morover, this thread is hopefully useful for others, too.

Posted: Sat May 17, 2008 7:47 pm
by srod
Each thread is given it's own stack and so it will have it's own local variables. Static and global variables are not stored on the stack, however, and so each thread will see the same globals / statics.

Posted: Sat May 17, 2008 8:28 pm
by AND51
Ah, so if I think of the scenario with threads/network/buffer, each thread must provide it's own buffer on order to avoid any chaos?
The other way around: If I want to code universal procedures, I should only use static variables if there's no danger?

Posted: Sat May 17, 2008 8:35 pm
by srod
AND51 wrote:Ah, so if I think of the scenario with threads/network/buffer, each thread must provide it's own buffer on order to avoid any chaos?
Or take steps to ensure that only one thread can access the buffer at the same time etc.

If you require local variables which are persistent like static variables then (Windows only) you might want to look at thread local storage.

Posted: Sat May 17, 2008 8:56 pm
by blueznl
Euh, that's interesting...

So, STATIC vars are not always static, I guess?

Posted: Sat May 17, 2008 9:01 pm
by srod
Static variables are indeed always static in that they are persistent, i.e. they keep their values between function calls etc. The only thing is that they are not stored on the stack (else they wouldn't be persistent) and are, in PB's case, stored in the data section etc. This means that they are visible to all threads.

This is the same for all Windows programming languages and is why Windows offers the thread local storage facility.