Multithreaded, Win32, Debug stack size

BlitzMax Forums/BlitzMax Programming/Multithreaded, Win32, Debug stack size

matibee(Posted 2013) [#1]
Running the code below causes a stack overflow only in MT-Debug builds;

SuperStrict 

Type thing
	Field vals:Float[12]
	
	Function Create:thing()
		Local a:thing = New thing
		Return a
	End function
End type

Local biglist:TList = New TList

For Local a:Int = 0 To 150000 - 1
	Local t:thing = thing.Create()
	biglist.addlast( t )
	If ( a Mod 1000 = 0 ) Print a
Next

Print "done!"


but if I comment out the biglist.addlast() there's no problem.

I've tried adjusting the dwStackSize parameter of the Windows CreateThread function calls to no avail (http://msdn.microsoft.com/en-gb/library/windows/desktop/ms682453(v=vs.85).aspx). It's currently zero.

Is there a bug somewhere in BMax or am I being unreasonable here?


col(Posted 2013) [#2]
Hiya,

The garbage collector seems to throw up in multithreaded apps. One solution is to set it to be aggressive which is undocumented and probably unsupported due to being undocumented. You could also try setting it to manual but then you'll see lags and hiccups when you switch it back on and the collector does it thing. The aggressive collection collects pretty much immediately with practically zero slow down althougj there is an overhead obviously but with some good design it shouldnt really pose a problem.

Use

GCSetMode -1

for an aggressive collection. Worth a try.


Derron(Posted 2013) [#3]
on linux there is no problem (i know you mentioned it is win32).


But windows finishes without error while not finishing the loop


I also removed the local variables without any change, so the GC has less to do, this changed nothing.

What is way more remarkable:

Same object:
Local t:thing = New thing
For Local a:Int = 0 To 150000 - 1
	biglist.addlast( t )
	If ( a Mod 1000 = 0 ) Print a
Next

ends at "95000"


String:
For Local a:Int = 0 To 150000 - 1
	biglist.addlast( "t" )
	If ( a Mod 1000 = 0 ) Print a
Next

ends at "95000"


New objects:
For Local a:Int = 0 To 150000 - 1
	biglist.addlast( new thing )
	If ( a Mod 1000 = 0 ) Print a
Next

ends at "124000"


New objects returned from an extra function call:
For Local a:Int = 0 To 150000 - 1
	biglist.addlast( thing.Create() )
	If ( a Mod 1000 = 0 ) Print a
Next

ends at "107000"


This is hmm... while I understood extra function calls are not the best.... I do not understand why "new objects" are working "better" than the "same object" approach


col(Posted 2013) [#4]
Another option would be to tell the linker to use a bigger stack for the main thread. Changing the stack size for CreateThread will work for when you spawn child threads not for the MainThread.

To adjust the stack for the MainThread use

Import "--stack 5242880" ' Tell the linker we want a 5Mb stack

at the top of your main file.

EDIT:- Looking through the standard bmk source, Mark sets the default stack size only on Win32 to 4194304 ( 4Mb ). This is more than likely the issue.


matibee(Posted 2013) [#5]
Thanks for your input guys.

But windows finishes without error while not finishing the loop


not without error for me. It stops with a default beep. Applications don't normally stop this way, and very occasionally it did report a stack overflow.

I really don't understand what it is specifically about a TList that uses up so much stack space. There are no temporary variables being created during insertion that need to be cleaned up. Which leads me to the GC..

Col, you certainly know some tricks!

The aggressive GC mode didn't help. But, as above, I'm really not sure there is any GC'ing to be done in my example above.

However, increasing the stack size with the Import "--stack " trick, has fixed it. I had to take it up to 24mb to get it to run my actual project code.

I'm going to code my own list type that works with chunks of heap memory and see if I can get round it this way. I'll be sure to report back.

Thanks again chaps.