Threaded BlitzMax!

BlitzMax Forums/BlitzMax Programming/Threaded BlitzMax!

marksibly(Posted 2008) [#1]
Hi,

Well, as many of you will have already noticed, a new 'threaded' version of BlitzMax is now available via SVN!

This is all highly experimental and will probably take some time to get right, but bear with us as I think it's worth taking the leap into threads-land! If nothing else, it's kind of fun...

How to/notes etc:

* After svn updating, you will need to 'bmk -a -h' to rebuild all modules in 'threaded mode'.

* After this, using '-h' with bmk to build apps can be used to build threaded mode apps. The IDE source on SVN allows you to do this via a new 'Threaded Build?' menu item. However, to rebuild threaded modules
you'll have to stick with raw bmk for now.

* Threaded mode is a bit like debug/release - it's static and can't be changed at runtime. Your app is either threaded or it's not.

* In threaded mode, the garbage collector is replaced with the "Boehm-Demers-Weiser" (bdwgc) collector. More information here: http://www.hpl.hp.com/personal/Hans_Boehm/gc/

* The new collector is slower than BlitzMax's ref-counting system. How much slower will depend a lot on the app. Although performance *will* improve, it will likely always be 'somewhat' slower. The bdwgc does however handle cyclic data structures (the ref-counter doesn't) which you may find useful even without threads.

* The debugger has been tweaked to ignore non-main-thread code.

* Exception handling has also been disabled for non-main-thread code. If non-main-thread throws an exception, the app will be rudely terminated.

* A new experimental Pub.Threads module has been added. Very, very simple for now but will grow and improve over time. See help/modules/System/Threads for the vast of array of powerful threading commands now at your disposal (Ok, there's just 7).

* Lots of OS specific stuff has its own rules when it comes to threading: GL contexts are 'per-thread'; dx devices are 'main thread only' (I think - perhaps just in fullscreen?); Mac's Cocoa is 'mostly' threadsafe etc. So don't expect to be able to 'load images in the background' suddenly/magically - all this stuff will take time to learn about and find the right approach for.

* The internal BBObject data structure will eventually change in threaded mode. Currently, the compiler still generates unnecessary ref-counting code but long term this will go. Anything that depends on BBObject->refs will break in threaded mode!

Finally, the current single-threaded ref-counting memory management will stay: My biggest fear in doing all this is that it will cripple 99.9% of apps for the sake of a handful of people actually capable of doing something useful with threads. I'm not exactly wild about having to now support 2 types of memory management but, well, let's just see what happens...!


Yahfree(Posted 2008) [#2]
Great news, this (and the 3d module) are the 2 biggest complaints i've seen on the forums, good work!

Prehapes have this build option built into the ide? for example: compile-threaded/run-threaded buttons? Of course after the experimental phase


REDi(Posted 2008) [#3]
Thank you! oh and, YAY THREADS :D


Ked(Posted 2008) [#4]
Because I'm an idiot, I'm going to ask, "What is threading?"


kfprimm(Posted 2008) [#5]
Wikipedia is your friend!

But yeah, this is great! Thanks alot!


Ked(Posted 2008) [#6]
A thread in computer science is short for a thread of execution. Threads are a way for a program to split itself into two or more simultaneously (or pseudo-simultaneously) running tasks (see also: fork). Threads and processes differ from one operating system to another but, in general, a thread is contained inside a process and different threads in the same process share some resources while different processes do not.

On a single processor, Multithreading generally occurs by time-division multiplexing ("time slicing") in very much the same way as the parallel execution of multiple tasks (computer multitasking): the processor switches between different threads. This context switching can happen so fast as to give the illusion of simultaneity to an end user. On a multiprocessor or multi-core system, threading can be achieved via multiprocessing, wherein different threads and processes can run literally simultaneously on different processors or cores.

Many modern operating systems directly support both time-sliced and multiprocessor threading with a process scheduler. The operating system kernel allows programmers to manipulate threads via the system call interface. Some implementations are called a kernel thread, whereas a lightweight process (LWP) is a specific type of kernel thread that shares the same state and information.

Absent that, programs can still implement threading by using timers, signals, or other methods to interrupt their own execution and hence perform a sort of ad hoc time-slicing. These are sometimes called user-space threads.

You couldn't have just typed that? Pssh, lazy. :P


ziggy(Posted 2008) [#7]
Great to see this public!
Been playing with this along this week and it works incredible well. I'm working on a sort-of parallels FOR implementation. I'm not sure if I will get anywhere with this, but it's being very fun.


xlsior(Posted 2008) [#8]
.


JoshK(Posted 2008) [#9]
Thank you for the info. I am glad to see this development.

My main use for threads is writing callbacks that won't crash for multithreaded Newton physics. Newton accepts a bunch of function pointers, and then the different threads call those functions during the physics update. I guess this requires some locking mechanism when a variable all threads can access is written to, although that situation can be avoided 95% of the time.

Other applications are definitely possible, but the physics is something I know I will get working and use it a lot within a few weeks, once it is ready.

For objects that must be stored in a global list or map, it is possible to work around the loss of ref counts by using a reference/instance class design and doing your own refcounts with the instances. In the instance destructor, you just decrement the reference object's "fake" ref count, and then remove it from the list when it reaches zero. I'll figure out something like that.

This will work great for our renderer, because the potential visiblity set routine is already divided up into big chunks that can be chucked at different threads, with no OpenGL calls or messy data exchange.


plash(Posted 2008) [#10]
I reckon this started, mostly, because of Max3D, Mark?


MGE(Posted 2008) [#11]
"* Threaded mode is a bit like debug/release - it's static and can't be changed at runtime. Your app is either threaded or it's not."

"Finally, the current single-threaded ref-counting memory management will stay: My biggest fear in doing all this is that it will cripple 99.9% of apps for the sake of a handful of people actually capable of doing something useful with threads."

PHEW! Thank you. As someone who has invested over a year learning Blitzmax I have no intentions of ever using a multi threaded version of Blitzmax. When games are already running at hundreds of frames per second on even modest hardware, there is simply no reason for me to change anything.


xlsior(Posted 2008) [#12]
PHEW! Thank you. As someone who has invested over a year learning Blitzmax I have no intentions of ever using a multi threaded version of Blitzmax. When games are already running at hundreds of frames per second on even modest hardware, there is simply no reason to change anything.


There are plenty of possible uses: e.g. spin off resource-intensive pathfinding to a seperate thread, or things like enemy A.I.

If those run in seperate threads, then you don't necessarily have to have all their work done before the next video frame is due.


MGE(Posted 2008) [#13]
oops... I edited my post to correctly state "no reason for ME to change anything". ;)


impixi(Posted 2008) [#14]
Very interesting. I’m experiencing significant performance increases for certain projects when making use of threads (running on my quad core system).

EDIT: Removed outdated example.


xlsior(Posted 2008) [#15]
impixi: It does seem to run faster on my core 2 Duo, but your threaded sample above does bomb out a bunch of times with: "***** UNKNOWN THREAD EXCEPTION *****"
(Hit and miss)


REDi(Posted 2008) [#16]
.


*(Posted 2008) [#17]
Excellent stuff :)


REDi(Posted 2008) [#18]
I seem to be getting much steadier/better FPS if I call GCCollect once a frame.

I've also noticed that calling GCSuspend and then using GCCollect in the main loop, doesn't actually free anything, unlike it would with the standard GC.


degac(Posted 2008) [#19]
Great news, thank you.


In threaded mode, the garbage collector is replaced with the "Boehm-Demers-Weiser" (bdwgc) collector



Finally, the current single-threaded ref-counting memory management will stay:



This means we have (will have) the possibility to choose to create SINGLE-THREADED or MULTI-THREADED applications. Perfect.
But every time do we need to rebuild all the mods to make them single/multi threaded? Or the 'new' bmk creates (automatically) 2 version of the mods?


Hotcakes(Posted 2008) [#20]
I believe multithreaded mods (which is not really correct, it's really more just 'old simple GC/new complex GC) are given a .mt extension, so yeh, two versions.


ziggy(Posted 2008) [#21]
But every time do we need to rebuild all the mods to make them single/multi threaded? Or the 'new' bmk creates (automatically) 2 version of the mods?

Yes there will be 2 versions, so you don't have to rebuild everything just to compile your app


degac(Posted 2008) [#22]
Thanks.
So I need to do 'BMK -a -h' once, and then select the option 'Build threaded' and Bmax does the work. Perfect!


Brucey(Posted 2008) [#23]
bmk makemods -a -h



ImaginaryHuman(Posted 2008) [#24]
Okay, so threads are really cool. Now, how can we find out (cross-platform) how many cpu's/cores the hardware is providing? It would be really useful to know if you are running on a multicore machine and how many cores you have available - ie if you wanted to create as many threads as there are cores, for example ???


Mark Tiffany(Posted 2008) [#25]
So I need to do 'BMK [b]makemods[b]-a -h' once, and then select the option 'Build threaded' and Bmax does the work. Perfect!

You'll need to do this every time modules get updated (Rebuild All Mods will *not* also do the threaded versions just yet).
So don't expect to be able to 'load images in the background' suddenly/magicall

I guess the best thing to do would be to load the file into memory in a bank, return that data to the main thread, and then load the image from the memory bank into a TImage object. Or something...


Ian Thompson(Posted 2008) [#26]
The O.S. will spread your total amount of threads amongst the cores, if there is more threads than cores then the thread execution will be split the core CPU clock up into individual threads... even single core CPU have simple hardware threading built into them...


Mauft(Posted 2008) [#27]
How "unsafe" is the threading in this release yet?

And how soon can we expect it to be "easily accessed" feature? ^^


Brucey(Posted 2008) [#28]
You'll need to do this every time modules get updated

Well, you can leave off the "-a" part if you don't want to spend half your day rebuilding everything.

So something like:
bmk makemods
bmk makemods -h

would build those that need it, after updating some of them. Obviously you need -a when you want to rebuild everything.

Just the same as usual, except for an extra step of including a -h build.


BlitzSupport(Posted 2008) [#29]

how can we find out (cross-platform) how many cpu's/cores the hardware is providing?



Well, here's the Windows version. Mac and Linux will have to be done by someone else!




Mark Tiffany(Posted 2008) [#30]
How "unsafe" is the threading in this release yet?

I rather suspect the "safe-ness" will relate to the code people try to write much more than the core code.

Well, you can leave off the "-a" part if you don't want to spend half your day rebuilding everything.

Well, duh! ;-P My point was more that you'll have to force a manual makemods each time and not rely on the menu option in the ide.


degac(Posted 2008) [#31]
I've run the Impixi program and I got (for the MT example) "***** UNKNOWN THREAD EXCEPTION *****"
The Debug tree highlithts (it changes at every run) the commands Cls, DrawPixmpa or DrawText...sometimes compares the window, sometime no.


markcw(Posted 2008) [#32]
Re: Processor Count.

In OSX Carbon has an MPProcessors() but Cocoa needs this:
http://www.cocoadev.com/index.pl?ProcessorCount

In Linux it's in the cpuinfo file:
http://paste.lisp.org/display/30651


Grisu(Posted 2008) [#33]
You guys rock! :)


Winni(Posted 2008) [#34]

Okay, so threads are really cool. Now, how can we find out (cross-platform) how many cpu's/cores the hardware is providing? It would be really useful to know if you are running on a multicore machine and how many cores you have available - ie if you wanted to create as many threads as there are cores, for example ???



It's actually quite irrelevant to know the amount of cores in your machine: You should use threads wherever it makes sense to move a bulk of operations into the background.

Even on a single core machine, your app would 'feel' more responsive because the user won't see the hour glass or beach ball while waiting for a job to be finished. And that's a very positive effect although that when measured with a stop watch the application might actually perform a bit slower because of the administrative overhead that multi-threading causes. But in return you will experience increased performance on a multi-core machine when you use threads.


GfK(Posted 2008) [#35]
Can this be used to show an animated loading icon for example? (one that won't freeze as the data is being loaded)


REDi(Posted 2008) [#36]
AFAIK, DirectX doesn't allow rendering in a thread (or at least you must only use it from the same thread the device was created with), so you would do it the other way around, draw in your main program and load the media in the thread.

I think DX9 has a multi thread flag that needs to be used for threaded apps, but that doesn't help us much, as things stand.


impixi(Posted 2008) [#37]
degac and xlsior:

On my Windows XP system (Intel Q6600 CPU - 2.4ghz quad core), the code I posted hasn’t crashed at all when run in release mode, but did seem to hang on one occasion when run in debug mode. However, the value returned by GCMemAlloced() is not correct.

In any case, it could be something I’m doing or not doing, related to threads. It’s not a field with which I’ve had any programming experience before…

I’ll try the code on my dual core OS X MacBook Pro later today and see if I have any problems…


ImaginaryHuman(Posted 2008) [#38]
I actually specifically want to be able to tell how many cores there are in total from all cpu units, and to use that number to create only that many threads - I appreciate your comments (various) about how the o/s will split things up for you and why what I want to do is irrelevant but I still want to be able to get a core count and launch that many threads - it's part of my design for a distributed computing system. It's not really worthwhile for me to just create threads on the offchance that they might end up on another core.

Thanks all for posting initial code for finding the core count.


BlitzSupport(Posted 2008) [#39]

However, the value returned by GCMemAlloced() is not correct.


It's considered invalid with the new GC, so you have to use Task Manager to monitor memory usage.


Winni(Posted 2008) [#40]
Gfk, yes, that would be one of the uses for multi-threading. ;-)

ImaginaryHuman, I knew that you had something specific in mind, and it looks like you want to do something where that approach makes perfect sense. It was just one of those general comments for the record. ;-)

markcw, thanks for that link!

For those of you who prefer OOP (like myself), here's a basic skeleton of an actual thread class with mini code to demonstrate that it works:

'A very basic abstract thread class. Derive your own class from it.
Type Thread Abstract
	Field handle:Int = 0

	'Call this to build and launch your actual thread.
	Method Start() Final
		Self.handle=CreateThread( Self.SpawnThread,  Object( Self ) )
	End Method

	'The thread factory
	Function SpawnThread:Object( data:Object) Final
		'Cast 'data' back to type Thread
		Local myThread:Thread = Thread(data)
		myThread.Run()
	End Function
	
	'This must be implemented by the derived thread class;
	'it contains what the thread(!) is supposed to do.
	'It is !-never-! called directly by the user.
	Method Run() Abstract
End Type


'Derived class - this will contain YOUR code for thread.
'Don't do anything fancy, just demonstrate that you're doing -something-.
Type MyThread Extends Thread
	Method Run()
		For Local n:Int = 1 To 100
			Print n
		Next
	End Method
End Type


'Create two instances and let them fly
Global T1:MyThread = New MyThread
T1.Start()

Global T2:MyThread = New MyThread
T2.Start()

Repeat
Forever




REDi(Posted 2008) [#41]
Winni, You need to call DetachThread otherwise the threads handle will not be closed.

*BUG* It seems CloseMutex() is missing the (BBMutex*) handle in threads.bmx


Retimer(Posted 2008) [#42]
Support for threading?

Looks like all that ranting of "blitz doesn't support us" by myself and the rest just got returned with a double slap to the face. Sorry for the previous disrespect in that matter, as you did come through spontaneously.

Now to play with this, woohoo !


ImaginaryHuman(Posted 2008) [#43]
When you're doing a repeat-forever, isn't that basically a third thread which is going to hog a lot of cpu time doing an infinite loop? Maybe stick a delay in there or something?


Winni(Posted 2008) [#44]
Yep, that's right. It should come before the end of method 'run'.

I've added a detach() method to the class skeleton, and I've also wrapped the OS X version of getProcessorCount() and it seems to work. It's actually not counting the CPUs, but the cores, by the way. When you're on Windows, getProcessorCount() should perform the code provided above by BlitzSupport.

Somebody still needs to do the Linux version.

I've put everything that I have so far into a module. It can be downloaded from here.


REDi(Posted 2008) [#45]
Yep, that's right. It should come before the end of method 'run'.

I'd say it would be better in the SpawnThread function, so the thread returns properly instead on being terminated. also worth setting "handle" to 0 after detaching the thread, you should then add another detachthread in a delete method that checks that the thread hasn't already been deleted ( if handle<>0 detachthread() ), just in case the class gets GCed. You could then also use the handle in a Status method to work out if the thread is still active or not (as so far we dont have a function for that yet)

Just my 2p :)


Winni(Posted 2008) [#46]
Hmm. That's a rather scary thought: Can the class actually get GCed while the thread is still running? If so, then this is a serious problem and would be a bitch to debug.

I'll change my ThreadClass mod following your 2p - what you say makes a lot of sense. It's on the download page of my blog now, in case somebody wants to look at or add to it. getProcessorCount() is still waiting for a Linux implementation. ;-)


Winni(Posted 2008) [#47]
I think detaching the thread should be handled in Start(), not in SpawnThread() - Start()'s context knows the valid handle.


REDi(Posted 2008) [#48]
but then your thread will die as soon as you create it. "myThread" in SpawnThread knows the handle ( myThread.handle ;) ).

*EDIT* Actually no, it seems that detachthread doesn't currently terminate the thread if its still running.


Winni(Posted 2008) [#49]
Good point, and again, you're right. ;-)

Strangely enough, the code still ran through exactly as it did before - but that could have been a coincidence.

Anyway. Another update on its way.


Regular K(Posted 2008) [#50]
Thanks mark for multithreading.

I'll be needing it soon...


REDi(Posted 2008) [#51]
could we have something like...
?Not threaded
	' allow non-threaded build of threaded modules.
	Function CreateThread:Int(entry:Object( data:Object ),data:Object) ; EndFunction
	Function DetachThread(thread:Int) ; EndFunction
	... blah blah
	' complain if this module is used in non-threaded mode.
	RuntimeError "Threading mode required!"
?

defined in threads.bmx, because atm it complains if you use threading commands in a module and run non-threaded "build modules", as we cant use nested conditional compiling it can be it quite awkward to remedy. ie: if you need ?win32 + ?threaded on the same lines of code.


Yan(Posted 2008) [#52]
For those of you that may want to tinker with this stuff from within the CEIDE (and missed the other thread)...

http://www.blitzbasic.com/Community/posts.php?topic=80119#902918


GfK(Posted 2008) [#53]
Is there any benefit to using this on single core systems?

Sorry if that's a stupid question but having used Blitz exclusively for almost the last decade, I don't know about these things.


GaryV(Posted 2008) [#54]
Is there any benefit to using this on single core systems?
Yes


Ian Thompson(Posted 2008) [#55]
Sorry if that's a stupid question but having used Blitz exclusively for almost the last decade, I don't know about these things.


Yes, even single core CPUs have hardware threads, its the most efficient method of doing tasks concurrently.


Scaremonger(Posted 2008) [#56]
Exciting times eh? Thanks Mark.


xlsior(Posted 2008) [#57]
Is there any benefit to using this on single core systems?


Yes -- especially since single core systems can also have optimizations like Hyperthreading where it can start executing new commands before the current ones have exited the CPU pipelines. Obviously not as efficient as an actual multi-core chip, but it can still give a noticible difference.

Obviously (?) you may not gain a huge speed increase on single core (and it may be detrimental in some cases thanks to the supposedly slower new garbage collection system used for threading) but it's definitely worth trying.


Wiebo(Posted 2008) [#58]
Sounds awesome! Please get it in the regular release as quickly as you can 'cos I don't use SVN =]


Grey Alien(Posted 2008) [#59]
Can this be used to show an animated loading icon for example? (one that won't freeze as the data is being loaded)
That's the main purpose I'd use it for too initially.


xlsior(Posted 2008) [#60]
Can this be used to show an animated loading icon for example? (one that won't freeze as the data is being loaded)


Apparently you can't (yet?) load your images themselves by a secondary thread and have them be available to the main thread, but

I do wonder -- Can you have the main program spawn a second thread that displays the animated icon while the main program itself loads in all the images?

Can the worker thread load its own animation graphic from disk and just twiddle it thumbs animating it, or won't it have access to draw to the screen at all?


REDi(Posted 2008) [#61]
Well I've just knocked together a little test program and it seems to work fine! but I'll leave it running for a while to see if anything untoward happens.

I didn't think this was possible because of a statement in the purebasic docs that reads...
Note: Don't use DirectX inside threads (MS Windows limitation)! If you need to display graphics in threads use Images and 2DDrawing instead.

But so far it seems to be working very well! :)

*EDIT* here's a simple test app, first choose an image (not a massive one) then a song, the song will be loaded in the main thread, and the image will be drawn with the new thread. the music will be loaded over and over again to simulate loading a lot of media.


The window isnt very responsive because the main thread is busy, but I suppose in full screen it wouldnt really matter, still it would be better the other way around with loading in the thread and drawing in the main thread.

*EDIT* updated


Tachyon(Posted 2008) [#62]
I haven't yet dove into this wonderful Threads module yet, but I have a few questions regarding what it is good for? Obviously, I know the benefit to breaking computationally intensive tasks into multiple threads for increased speed, but I have also read how this feature won't be of benefit to 'everyone' based on what your program actually does.

So, I guess I would love to hear some opinions on exactly what this means to the average game developer? In a real-world game such as Fairway Solitaire, Runes of Avalon or Eschalon, what kinds of fantastic benefits or tricks can be performed by having the code threaded?


Gabriel(Posted 2008) [#63]
Games are not ideally suited for threading, and particularly not relatively simple (technically) ones. I guess the most obvious ones would be input, sound, physics and resource loading.

Threading your input means that your game is always responsible even when it's chugging along quite badly, struggling with some heavy duty graphics. Unresponsive input is a big turn off.

Threading your audio ensures that it never skips and there are no unfortunate clicks and pops when things slow down a bit. Mind you, most (third party) audio engines do this anyway, I guess.

Threading your physics is fairly obvious because it's computationally expensive, but I imagine most physics engines are already doing this, and you don't need threading in your language to use it.

Threading your loading means you can keep the screen animating while you load, or even (in advanced cases) stream in the next section of the game world while you play.

Unless you're doing something with some seriously heavy duty physics, I doubt you'll notice or need any speed improvement. Indeed, on a single core machine, you'll even sacrifice a tiny bit of speed. It's more about ensuring the separate components of the game are all responsive.

There are other game-related features that don't necessarily end up in a game which would benefit, of course. If you were writing a lightmapper, then having the application remain responsive and even update itself with a progress bar would be great. Not that you can't do it without threads, but it's easier with.


xlsior(Posted 2008) [#64]
Well I've just knocked together a little test program and it seems to work fine! but I'll leave it running for a while to see if anything untoward happens


It appears to work just fine on my machine -- interesting sample, thanks for sharing! :-)


Grey Alien(Posted 2008) [#65]
Thanks for the explanation Gabriel. To be honest I only see it as useful for loading whilst animating on the types of games I make. Maybe I'll try this for my next game. Thing is most, players aren't bothered by 1 second loading times anyway :-)


DStastny(Posted 2008) [#66]
@Gabriel nice example.

FYI you dont need the mutex on the Terminate since in the thread context you are just reading it. Externally you are writting it. Worst thing to happen is it will continue run one more time.

Mutexs are expensive use them only on data that you are reading and writing from different threads.

DStastny


markcw(Posted 2008) [#67]
Not that I'm much of a game developer, but I wouldn't use threading in a game. Exceptions would be network or physics intensive games which are rarely made. From the sounds of it, non-threaded BMax would be faster for most 3d games and maybe all 2d games. I think that's why threading was never added until now, when Mark finally gave in. Still, it's nice to have it as an option.


TomToad(Posted 2008) [#68]
Just tried writing a simple particle engine using a thread to update the particles. Probably not the best way to handle this, but I did get some weird side effects with the GC.

First, run this example while you have the task manager open so you can see how much memory is being used. The top number is the number of particles being rendered and the bottom number is the framerate. Notice that when no particles are being drawn, the framerate is 60fps. Now hold the left mouse button and move around to fill the window full of particles. You'll notice that the memory usage will creep up for a while. It does stop eventually, but it never goes back down. Also, at some point you will notice that the frame rate will drop.

Now release the mouse button and wait for the particles to disappear off the bottom of the screen. First you'll notice that the memory usage never drops. It will stay at its maximum level. Also you'll notice that as there are less and less particles to render, the framerate will actually drop! On my machine, I'll get 40-60 fps with the screen full of particles and only 30-40 once all the particles disappear! This is strange as there are no particles to update and no particles to render.
Now uncomment the GCCollect(). The memory problem is still there, but the total memory usage only ends up being about half as before. The framerate though, will creep back up to 60fps as the particles disappear from the screen. So do you need to have a GCCollect() when using the threaded GC?

System specs AMD Athalon 64 Dual Core 5000+ 2.6Ghz
2gig Ram
Vista Home Premium SP 1
BFG NVidia GeForce 8800 GT OC 16X PCI-E 512MB



Kurator(Posted 2008) [#69]
Q6600, 20k particels, no framerate drops, mem usage goes up to 20k and stays there

with gc on (on every flip) in naturally decreases framerate, and memory usage stays low as 8k.

if you want do reduce mem usage, create a gc thread with a specific timer - say 1000 msec, so you don't have to call it every flip :)

i will test your programm again when i installed the latest fixes from svn


ImaginaryHuman(Posted 2008) [#70]
I can think of many many ways that theads are useful for applications, like with MaxGui, you can have things rendering and calculating and processing in parallel, you can have multiple windows open at the same time doing processing in parallel, etc.

I do agree that the uses in games is less obvious but I think in part this has something to do with a) that most games are very linear and b) we just haven't had the freedom before to do things in parallel so game design hasn't explored the possibilities.

I would definitely try to get file access into a thread but only if that helps to completely remove file loading from the user's perception of what's going on. You should be trying to load files without causing the user to wait around doing nothing, regardless of whether it's threaded, it's just that a thread for file access would help to achieve that (e.g. load your files while the user is operating the menu buttons, reading some important text/instructions, or viewing a cut-scene).

A thread would definitely help with spooling data from disk during gameplay, like for a large terrain landscape or extra models or level data, but only really if you have multiple cpu cores - doing it on a single cpu isn't really going to give you anything other than the ability to pretend that you're doing two things at once, and that amounts to a coding technique. Instead of managing the concurrent operations youreself you're just asking the o/s to conveniently switch between then for you to try to complete both in virtual-paralellism.

I think mainly larger more advanced game engines will benefit the most from threads, but less so for simpler stuff.


Retimer(Posted 2008) [#71]
From the sounds of it, non-threaded BMax would be faster for most 3d games and maybe all 2d games


From a developer stance, and working with custom tools and servers, threads are oh so beautiful. Having a quad core server with an application that only uses one core was depressing.

Today i've started to faithfully integrate threads into my editors and servers. I'm astonished at how stable blitzmax threads currently are after such little time, and ofcourse, due to it being blitz, finding it easier to work with. Thank you so much Mark.S and anyone who assisted this addition. I have a permasmile that won't even let me drink my coffee.

I think blitzmax is back into the competition with other languages (including for 3d), even for application development. This is grand.

I'm sure leadwerks is in a state of awe even moreso lol.


TomToad(Posted 2008) [#72]
robobimbo: Try changing the TParticle.Create(100,MX,MY) line to something like TParticle.Create(200,MX,MY). Leave the 'GCCollect() line REMed for now.
The idea is to get so many particles going at once that the frame rate drops. Get enough going so it drops to something like 40fps.
After that, let go of the mouse button and let all the particles fall off screen. You would expect at this point that the framerate would go back up to 60, just like it was before you started spewing out particles, but on my machine, the framerate actually drops even further!
If your machine is acting like mine at this point, try it again with GCCollect() active. Notice how the framerate returns normally after the particles disappear? It just seems that particles are being processed even though there are no more references to any, and those "pseudoparticles" are not getting cleaned up by the GC without an explicit GCCollect().


TomToad(Posted 2008) [#73]
Ok, it seems that when a thread grabs CPU cycles, it doesn't want to give them back. I rewrote my example to destroy the thread when there are no particles to render and respawn it when new particles need to be updated. Now the framerate goes back up to 60 when no particles are left. Also, before my cpu usage was about 60% with a screen full of particles, but dropped to 50% when no particles were present. Now, with the change, CPU usage drops to about 3-4% indicating that it was the spawned thread grabbing my CPU (dual core).
Here it is again with the change. Also, I changed the program so that only the main thread adds or removes particles from the list, removing the need to use LockMutex().



ImaginaryHuman(Posted 2008) [#74]
One other thing that I'm planning to use threads for, is to run multiple scripts in a script engine at the same time. Each thread can have its own instance of the script interpreter/execution engine and thus run scripts in parallel, increasing the total amount of script execution that can be done on multicore cpu's, plus providing the flexibility of running two or more scripts `at the same time`.

Each of my script execution engines has its own system of `processes` and a pre-emptive scheduler, so it can actually do the equivalent of multitasking threads without using real threads, but `real threads` make it even more capable of using the available CPU power, particularly if the script calls some function that is particularly time consuming and not very fine grained - the o/s would be able to give time to some other task in the middle of it. So overall threads would allow for more accurate timing and less `locking up`. I plan to run one script engine on each core of the cpu, so one thread per core.

One thing that you can't do with threads, though, is manage their distribution amongst cores or the way in which it would multitask or schedule other threads to run, because that's something usually managed by the o/s. But with some ingenuity I'm sure it should be possible to get threads to cooperatively multitask or something.


BlitzSupport(Posted 2008) [#75]

One thing that you can't do with threads, though, is manage their distribution amongst cores



I haven't done it yet, but, on Windows NT at least, threads can be forced to a particular processor, or a 'preferred' processor specified. From what I've read, Microsoft advises just to leave it all to the OS though.

This example forces a whole process onto a specific CPU (right-click on the Task Manager entry and select "Set Affinity" to see the result), but you can do similar for threads using SetThreadAffinityMask or SetThreadIdealProcessor:




Kurator(Posted 2008) [#76]
I created a simple Threadpool-implementation.

A Threadool creates a defined number of Threads. These Threads do not die after their work is done, so there is no syscall overhead when they are needed again. They rest in a pool, used simply when they are needed and some work has to be done.

The work is organised in so called "Tasks"

You can create 1000's of different Tasks, and add them to an Workingqueue - The queue is simply First in - First out.

The queue simply looks for unused threads in its threadspool, and assigns them some work.

It's pretty effecient:



I'm using a Quadcore Intel Q6600 (2.4 GHz)

Here are my results with different numbers of threads created on initialization:

1 Thread in Threadpool: 48818 ms
2 Threads in Threadpool: 24178 ms
4 Threads in Threadpool: 12234 ms
8 Threads in Threadpool: 12230 ms

So it scales pretty lineary (of course caused by the simple workload with no raceconditions :) )

Have fun with it


AlexO(Posted 2008) [#77]
Grey Alien

Thanks for the explanation Gabriel. To be honest I only see it as useful for loading whilst animating on the types of games I make. Maybe I'll try this for my next game. Thing is most, players aren't bothered by 1 second loading times anyway :-)



One application you may find useful for casual games would be to thread particle engines. This would allow more intricate/elaborate particle animations with minimal hit on the rest of the game engine.


Winni(Posted 2008) [#78]
These developers wrote a few interesting things about multi-threading in games:

http://www.powerof2games.com/node/36


plash(Posted 2008) [#79]
* After svn updating, you will need to 'bmk -a -h' to rebuild all modules in 'threaded mode'.
That would be 'bmk makemods -a -h' ;)


Banshee(Posted 2008) [#80]
Thank you for taking the time to do this module Mark. I am really exciting to have the chance to play around with threads, not just learning something new, but harnessing the full power of modern systems - fantastic!

My question:
Am I missing the obvious, but i've no idea how to access the SVN ?


ImaginaryHuman(Posted 2008) [#81]
Is SVN for Windows only?


Banshee(Posted 2008) [#82]
No SVN is a technology, like FTP except it is specifically for source code and allows multiple programmers to work together on the same source and handles merging of files, and allows you to roll back to old versions. It's like a central repository for programming teams to work with that is fully historical. It's very powerful, and apparently Blitz has one with code I want on it ! lol


GfK(Posted 2008) [#83]
No SVN is a technology, like FTP except it is specifically for source code
Not completely accurate. You don't *have* to use it for source code. You can use it for any file that gets revised from time to time.


Mark Tiffany(Posted 2008) [#84]
Am I missing the obvious, but i've no idea how to access the SVN ?

SVN thread
Seb's guide (Maxgui specific, but should help)

Is SVN for Windows only?

No. Google SVN and your platform of choice. I'd suggest TortoiseSVN for Win, and RapidSVN for Linux. I believe SmartSVN is okay for macos.


Banshee(Posted 2008) [#85]
Lots of flaffing around learning about bmk, but i'm there - it's terrific ! Cheers Mark.


Banshee(Posted 2008) [#86]
Can I ask is there some guidance somewhere on mutexing, it's a new concept to me so I wanted to check a few things?

Do I only need to lock data down if it is being written too? Or would that cause problems if a read operation started just before a write operation - should I lock all data down?

I've wiki'd on mutexing but it doesnt reveal much except what the concept is and the docs are, well, not written yet :) Can anyone offer some basic guidance on it for me please?


Mark Tiffany(Posted 2008) [#87]
While I've not read this (or used threading yet!), Brucey's posted links to pages on this site before, which while not max specific, look like they might help with concepts:

MUTEXES


Brucey(Posted 2008) [#88]
Do I only need to lock data down if it is being written too?

You should lock all shared data access, both reading and writing, if you want to be sure of its state at the time you access it.

Unless of course, you don't mind reading data that may return out-of-date results? (a bit like a dirty-read in database-land) - but most of the time you will want all access locked.


The latest SVN also has some new functionality - Condition Variables. They allow you to have a thread "wait" inside a locked section. This lets you have a much finer grain of synchronisation between threads. While "waiting", the thread releases its lock, allowing others to lock/unlock the mutex. When signalled, the thread regains its lock, and carries as before.

This is a very basic example of using a condition variable :



You just need to be careful when crafting your thread interaction, that you don't get into a situation that Thread A has a lock on Mutex 1, and is waiting to lock Mutex 2, while Thread B has a lock on Mutex 2, and is waiting to lock Mutex 1... oops.. :-p


Retimer(Posted 2008) [#89]
You just need to be careful when crafting your thread interaction, that you don't get into a situation that Thread A has a lock on Mutex 1, and is waiting to lock Mutex 2, while Thread B has a lock on Mutex 2, and is waiting to lock Mutex 1... oops.. :-p


What about Thread Alpha, Thread Theta, Thread Z and Thread Magneta running a perpendicular wait to Mutex 18, 76 and 22? lol..lets not make it confusing for people or anything =P


Otus(Posted 2008) [#90]
Cool! Why haven't I visited the site for a few days?!?

*Starts TortoiseSVN...*


Grisu(Posted 2008) [#91]
I'm new to this.
Could the bmx compiler benefit from threading?
I.e. shorter build times for modules and our apps?


ImaginaryHuman(Posted 2008) [#92]
Also now that Max has threading, couldn't there be a threaded version of the basic libraries of BlitzMax *itself*, to provide things like asynchronous file access as part of the language, just as a starter?


Brucey(Posted 2008) [#93]
Could the bmx compiler benefit from threading?

Messy... it would have to build an ordered process hierarchy, so that dependent modules get built first. Modules that then had no other dependencies could then in theory be compiled at the same time.
I've given it some thought, but haven't actually tried it yet. Not sure how much difference it would make - especially if you already turn on the "super quick build" option.


plash(Posted 2008) [#94]
Also now that Max has threading, couldn't there be a threaded version of the basic libraries of BlitzMax *itself*, to provide things like asynchronous file access as part of the language, just as a starter?
Threading is not standard, yet. ASync would be interesting, but unless your loading a lot of files at once it won't be much use (loading 1 file, have to wait until it is finished to use it.)


skn3(Posted 2008) [#95]
Cool!

Just tried this on my lunch break (after hassling with bloody MinGW needing a restart for path to take effect). Works really well!

I can see a few immediate uses for this. One of those being a network library. Which I think I may have to make!!! Could open a new thread for sending files. Dealing with database updates, etc! Oh that and finally the ability to have tcp that doesn't screw your framerate over!

Have struggled immensley in the past making network libraries, having to resort to splitting packets into tiny sizes, using a seperate exe with local coms, you name it I have done it!

Awesome stuff, thanking you greatly Mr Mark Sibly!


Dreamora(Posted 2008) [#96]
Somehow I missed this news, have not been much on the board here lately.

Great to see this happening even if pure experimental. Hopefully at some point with semaphores or even better monitors. Mutex are, thought nice, a near guarantee to run into walls depending on the implementation which don't exist with Semaphores
Luckily I won't have those issues as the threads work on distinct stuff and only need Mutex to block the access to queues temporally when adding / removing jobs to work on.
There are various uses for it on my work (script handling, networking, potentially the MySQL related stuff as well. all feeding global lists with data for the main thread and vice versa). Potentially it will also allow me to push my "node" approach even further. Right now its main app - tcp - node and pushing many distinct nodes that have to replicate the data. With the threads part of that can be gathered on the main app, making the node potentially a fully distinct unit for larger scale / math jobs instead of just a replacement for threads


Thank you very much for this chance :)


Arowx(Posted 2008) [#97]
Just getting to grips with this as I'm very keen to thread the loading of music in the background!

Got threaded building working, and the Coffee,Inc example appears to work fine!

But the play and load sound whilst loading and displaying an image example from REDi keeps failing to load the image, in my case a small png failing with a Null exception when it gets to the MidHandleImage(Image) line!

Is anyone else having this issue with this example?

Running on Vista, tried to change the AudioDriver to OpenAL to get some sound playing (a known problem with Vista) but currently no joy!


Mark Tiffany(Posted 2008) [#98]
From mark's post at the top:

* Lots of OS specific stuff has its own rules when it comes to threading: GL contexts are 'per-thread'; dx devices are 'main thread only' (I think - perhaps just in fullscreen?); Mac's Cocoa is 'mostly' threadsafe etc. So don't expect to be able to 'load images in the background' suddenly/magically - all this stuff will take time to learn about and find the right approach for.


i.e. if you load an image in a separate thread, it may exist in a separate graphics mode, and hence not be accessible.

I suspect the threadsafe way to load an image or sound in a background thread would be to actually load it into a bank, pass that bank back to the main thread, and the main thread can then create the image / sound.

But I'm no expert on threading, and haven't played with the goodies yet myself!


Kurator(Posted 2008) [#99]
Hm,

I also never tried it, but I think you can load it in another thread, but only do the Draw-Call in the main-Thread


JoshK(Posted 2008) [#100]
I think loading files like textures asynchrously is a little overblown. If you designed your file format right, the loading should not take much time at all. The main delay is in uploading the data to the video card, which must be done by the main thread.

I have heard DX11 is going to be a multithreaded API, i.e. each thread can access it, but we'll see how that works out in practice.


ImaginaryHuman(Posted 2008) [#101]
Presumably if you use LoadPixmap instead of LoadImage, you can have one thread loading pixmap data and another thread (or main thread) can be uploading to the graphics card.

It would be nice if you could be doing both at the same time, ie as the pixmap data is being streamed from disk, it starts to be uploaded to the graphics card, but that would require mutexes/conditions to be used to stop the main thread from reading data that hasn't been loaded yet, which presumably would mean having to add mutexes/conditions to pixmap loader (doable) and the uploader (probably, maybe not doable).

A way to avoid having to do those locks would be to be loading several pixmaps and to be just `one pixmap behind` in your upload to the graphics card. ie you load one pixmap, then when it's done you start the main thread uploading it to the graphics card while you load another pixmap in the second thread, and so on.


ImaginaryHuman(Posted 2008) [#102]
So when do threads stop being `experimental` and start being something `official`?


Galaxy613(Posted 2008) [#103]
I was thinking, couldn't you use threads to make a animated loading screen? While stuff is loading in the main thread, you could have a secondary thread drawing a animated loading screen at the same time...


Kurator(Posted 2008) [#104]
You can do it the other way round, Drawing Operations have do be done from the main thread, you can load Data in a Backgroundthread


itsdanreed(Posted 2008) [#105]
I've been waiting for threading for sometime, since I'm mostly doing some network server-client experiments this shall prove most usefull indeed.


ImaginaryHuman(Posted 2008) [#106]
What kind of range of values are returned as the thread handle when you create one? Does it start at 0 and increment from there each time you create, or is it just some random number up to 2^31?

ie how can I use the handle to provide storage local to a thread?


Kurator(Posted 2008) [#107]
The handle ist nothing but an identifier for the os to manage its threads. The number returned is depending on the actual system state, threads since system startup, os version, threadlib used and last but not least depending on the platform (win, mac, linux)

to provide storage for your threads just use local varaiables and types. The thread itself can return :Object, so it is up to you what Data you want to get back, also you can pass in a :Object as a Parameter


ImaginaryHuman(Posted 2008) [#108]
I understand the use of locals and types and all that, that part is obvious. What I was asking is how to make sure a specific thread is referencing a specific type or array or index, even when it's doing exactly the same tasks with the same code as other threads. Obviously if I run a thread which calls MyFunction(), and that function does some processing which accesses a Global called MyGlobal, then other threads that call MyFunction are also going to be accessing MyGlobal, which is not what I want to happen. I want each thread to access a unique global which is somehow associated with that thread and only that thread, even though it's globally accessible data. (it must be global but just not used by every thread).

You spoke about passing in an object - I understand that object can't be just an Integer, it has to be a custom type. So if I pass it a custom type, how would the functions executed by that thread access that instance of that custom type?


dynaman(Posted 2008) [#109]
> how would the functions executed by that thread access that instance of that custom type?

You will need to pass the instance of the type to the functions as a parameter.


ImaginaryHuman(Posted 2008) [#110]
Ouch. That's a no-go. What if the type instance were in a Global array and the array index itself was not passed the program, but rather the type instance is passed? Could the functions then access the type instance without having to pass it to them as a parameter?


Armitage 1982(Posted 2008) [#111]
Does cyclic references explain here by Ziggy is about to change with the new Garbage collector introduced with Thread ?
http://blitzmax.com/Community/posts.php?topic=63263#706547

I'm also wondering why this new GC will only be available in the thread mode...


Yan(Posted 2008) [#112]
Does cyclic references explain here by Ziggy is about to change with the new Garbage collector introduced with Thread ?
Yes. It's my understanding that the BDWGC can handle cyclic references.



I'm also wondering why this new GC will only be available in the thread mode...
Mainly because it's slower than BRL's GC, I believe.


Armitage 1982(Posted 2008) [#113]
Thanks
I will wait official release to test it.
I found the actual GC pretty fast so it's not an issue for me.


Kurator(Posted 2008) [#114]
@ImaginaryHuman: If you need a "own" global, you have to "clone" the existing Object and pass the Copy insider the ThreadFunctionality.

Alternatively you can write a ThreadWrapper Class extending the Existing TThread Class and add some of the members you want to have inside.


ImaginaryHuman(Posted 2008) [#115]
but then you have to pass the object to all functions that the thread calls.


TomToad(Posted 2008) [#116]
Anybody else get errors with this?
SuperStrict
Global Mutex:Int

Function MyThread:Object(data:Object)
	LockMutex(Mutex)
	Print "Inside the thread"
	UnlockMutex(Mutex)
End Function

For Local i:Int = 1 To 10
	Local ThreadHandle:Int = CreateThread(MyThread,Null)
	DetachThread(ThreadHandle)
Next

WaitKey()



Kurator(Posted 2008) [#117]
You just declare the Mutex, but you didn't call the Init-Function

Global Mutex:Int = CreateMutex()

works


Armitage 1982(Posted 2008) [#118]
Look like threaded version of BlitzMax is robust.
I wonder when it's gonna be official :)
So much stuff you can do with this to speed up games and applications !


ImaginaryHuman(Posted 2008) [#119]
I guess when the next official full version or update gets released, and not via SVN only.


ImaginaryHuman(Posted 2008) [#120]
I'm trying to jump on the SVN bandwagon on OSX but I'm having problems with BMK. The SVN part of things went okay and I have the max files in Applications/BlitzMax1.30SVN folder. I used my original blitzmax 1.30 to compile the IDE. But now I need to bmk makemods -a -h to get the threaded version to work.

I went to the terminal and did:
cd /applications/blitzmax1.30svn/bin
ls

It shows the presence of bmk and the other contents of bin, so I type:
bmk makemods -a -h

but all I get is that the command is not found. I figured out to do `open bmk` but that won't let me pass parameters to it. I tried to `exec` it but that didn't work. What am I doing wrong or missing?


Kurator(Posted 2008) [#121]
try like in unix ./bmk makemods -a -h


xlsior(Posted 2008) [#122]
Under UNIX, Linux, BSD, OSX , (and the other UNIX-derivative operating systems) your current folder is NOT in the path by default, unlike DOS/Windows.

To run a program in the current folder, you'll have to prefix ./ to it.

There are a couple of other 'special' indicators:

./ = current folder
../ = parent folder of the one you are in
../../ = two folders up from the folder you are in
../../../ = three folders up from the folder you are in, et.
~/ = the user's home directory

'.' for your current folder and '..' for the parent also work under DOS/Windows, but there the current folder is always checked before the other folders in the path, so normally you don't need to explicitely specify it.


ImaginaryHuman(Posted 2008) [#123]
./bmk makemods

works, and

./bmk makemods -a

works, but

./bmk makemods -a -h

does not, it says there is an error in the command. I thought maybe I'd overwritten bmk with a version that I compiled, so I redownloded it via SVN, but still the same. I can't get the -h to work?


ImaginaryHuman(Posted 2008) [#124]
Ok I got it to work - I figured out that I needed to download the DEV version of Blitzmax, not the 1.30 version (doh). No wonder.

After that
./bmk makemods -a -h

worked no problem. Then I had to build maxide from the command line, because the 1.30 IDE does not recognize some modules/commands so can't compile the ide ...:
./bmk makeapp -t gui -h -d ./../src/maxide/maxide.bmx

Now I see the threaded build option in the IDE and can access the threads module. Gotta test it out now! Thanks again for the help.


Regular K(Posted 2008) [#125]
Are there any known problems with MaxGUI and threads? I get some odd bugs when trying to manipulate a textarea in a thread (of course in between mutex lock/unlock)


grable(Posted 2008) [#126]
I get some odd bugs when trying to manipulate a textarea in a thread

On Windows, TextAreas are not thread-safe, though proper synchronization should fix that.
http://support.microsoft.com/kb/957833


Regular K(Posted 2008) [#127]
On Windows, TextAreas are not thread-safe, though proper synchronization should fix that.
http://support.microsoft.com/kb/957833


Hmm, thanks. Odd though, the textarea is disabled (so the user isn't editing it) and the command that edits it is wrapped in a lock/unlock mutex so its only edited by one thread at a time. Only thing I can think of is MaxGUI doing something I'm not aware of.


Htbaa(Posted 2008) [#128]
Maybe it has something to do with the events it's emitting?


Regular K(Posted 2008) [#129]
I managed to narrow it down to when the 'main thread' (whats the proper term?) tries to add a message before the thread finishes its own message, it craps out.

Function Msg(Text:String)
	DebugPrint "msg: locking mutex (" + Text + ")"
	LockMutex(MsgMutex)
	
	DebugPrint "msg: adding " + Text
	AddTextAreaText(Output, Text + Chr(13))
	
	UnlockMutex(MsgMutex)
	DebugPrint "msg: unlocking mutex (" + Text + ")"
End Function


an example of the text printed into the debug console would be:

thread: calling msg
msg: locking mutex (Called from 'Run' in 'TThread': this message should be added randomly every 50ms to 100ms)
msg: adding Called from 'Run' in 'TThread': this message should be added randomly every 50ms to 100ms
main loop: calling msg
msg: locking mutex (Called from main loop: this message should be added randomly every 50ms to 100ms)


so
the thread locks mutex, adds its message, but right before it unlocks the mutex the 'main thread' tries to add a message. The program hangs while the 'main thread'tries to lock the mutex.


Kurator(Posted 2008) [#130]
As far as i know, Win GUI is not threadsafe. Also in C# you may not acces the UI from a Background Thread


*(Posted 2008) [#131]
Will we see an official update (1.31) with threading soon? :)


Brucey(Posted 2008) [#132]
Mixing threading and native-GUIs is going to cause a lot of headaches, me thinks :-p

Basically, you probably don't want to be doing anything to the UI controls themselves outside of the main thread. If you stick to that rule, you should be fine.


Regular K(Posted 2008) [#133]
Mmkay, thanks. I managed to get around the errors by passing commands to the engine that are executed on the main thread.


ImaginaryHuman(Posted 2008) [#134]
I'm having a problem compiling the thread pool example by Kurator. It says it does not recognize the TList that's being defined in the field of the first custom type. Why would TList not be found when it's such a standard part of BlitzMax and the code isn't using a framework or imports?

Strict

' *** THREADPOOL CLASSES START ***

Type TWorkQueue

	Field nThreads:Int
	Field threads:TThread[]
	Field queue:TList

Identifier TList not found

Is it because the SVN IDE can't compile properly yet? Do I have to go to the terminal?

[Edit]It's also not finding TBank?[/edit]


plash(Posted 2008) [#135]
@ImaginaryHuman: That's strange.. The standard IDE definitely, by default, imports brl.linkedlist - perhaps it was a module change on the SVN side? (the standard imported module(s) do not import brl.linkedlist?)


ImaginaryHuman(Posted 2008) [#136]
When I try to compile a non-threaded app in the same ide I get different errors. I guess maybe this is just not ready for use yet, or are we supposed to import all modules?

Another question - load balancing. If my CPU has 4 cores, for example, and I am creating a thread pool, should I create just 4 threads, or would there be any benefit to creating more? If, say, each thread uses 75% of the cpu time for the core it's running on, it can't really be moved to another core or `split`, so does the o/s know to put each thread on a separate core? Or should I create like 16 threads and hope the o/s will distribute it more evenly?


Kurator(Posted 2008) [#137]
how many threads to put in a pool depends on how many threads are locked while working. so if you only use 4 threads on a quadcore - and one of the threads locks waiting for another you loose computing-power because one of the cores idling :)


ImaginaryHuman(Posted 2008) [#138]
Good point. Any idea about why your pool example doesn't compile?


plash(Posted 2008) [#139]
Any idea about why your pool example doesn't compile?
You have tried doing the imports, right?


ImaginaryHuman(Posted 2008) [#140]
No idea what needs to be imported. And why would I need to, anyway? Has this compiled okay for anyone else?


Kurator(Posted 2008) [#141]
It compiles for me when I tried it with my actual BlitzMax DEV - with the acutal IDE in this package


ImaginaryHuman(Posted 2008) [#142]
I'll have to download the sourcecode of the dev IDE again and recompile it. Does it need to be compiled *after* building multithreaded modules?


Kurator(Posted 2008) [#143]
Good question, I compiled after building the mt - modules


ImaginaryHuman(Posted 2008) [#144]
Tried that, still doesn't work.


ImaginaryHuman(Posted 2008) [#145]
I get the following errors when I am initially building modules:

Compiling:blitz.bmx
Archiving:blitz.debug.mt.macos.x86.a
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/thread_local_alloc.c.debug.mt.macos.x86.o has no symbols
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/win32_threads.c.debug.mt.macos.x86.o has no symbols
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/backgraph.c.debug.mt.macos.x86.o has no symbols
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/gc_dlopen.c.debug.mt.macos.x86.o has no symbols
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/specific.c.debug.mt.macos.x86.o has no symbols
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/pthread_stop_world.c.debug.mt.macos.x86.o has no symbols
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/checksums.c.debug.mt.macos.x86.o has no symbols
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/real_malloc.c.debug.mt.macos.x86.o has no symbols
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/pcr_interface.c.debug.mt.macos.x86.o has no symbols

Compiling:blitz.bmx
Archiving:blitz.release.mt.macos.x86.a
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/thread_local_alloc.c.release.mt.macos.x86.o has no symbols
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/win32_threads.c.release.mt.macos.x86.o has no symbols
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/backgraph.c.release.mt.macos.x86.o has no symbols
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/gc_dlopen.c.release.mt.macos.x86.o has no symbols
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/specific.c.release.mt.macos.x86.o has no symbols
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/pthread_stop_world.c.release.mt.macos.x86.o has no symbols
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/checksums.c.release.mt.macos.x86.o has no symbols
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/real_malloc.c.release.mt.macos.x86.o has no symbols
libtool: file: /Applications/BlitzMax1.30SVN/mod/brl.mod/blitz.mod/bdwgc/.bmx/pcr_interface.c.release.mt.macos.x86.o has no symbols

Some issue with blitz.mod? I don't get any of these errors when building regular non-threaded modules. Also if I build nonthreaded modules first then threaded ones, I can get the IDE to compile thread-using programs, but they crash.


ImaginaryHuman(Posted 2008) [#146]
I'm glad to say all other examples work for me, except the thread pool example which just bombs out.

On another note- could BRL put a command like `CPUCount()` as part of the threading module itself, to hide all the multiplatform c sourcefiles and such? Winni's module is nice but it's still a nonstandard module. Can this be made official?

Also, wouldn't the linux version be easily writeable in blitzmax code if it's just reading a text file?


foosh(Posted 2008) [#147]
Would it be possible to release a pre-compiled threaded version? Updating from SVN and trying to run the included threading example yields the following error:

Module does not match commandline module.

I've recompiled all the modules, and it still doesn't work.


TaskMaster(Posted 2008) [#148]
Did you build all modules in threaded mode?


ImaginaryHuman(Posted 2008) [#149]
A question about detach thread: If I call DetachThread and let it keep executing while I go about my business doing other stuff... when the thread gets to the end of its work/function will the thread actually `close` in the same way that CloseThread closes it, and be deallocated ie removed from the system completely, or do I still have to explicitly call CloseThread at some point down the road? Does DetachThread do the same thing as CloseThread but just automatically `when it's finished`?

I think the answer is that once I call DetachThread it will close when it's finished and will no longer consume any CPU time whatsoever, but I would like someone else's interpretation??

Thanks.


foosh(Posted 2008) [#150]
@TaskMaster: Yes, I used the -a -h flags.


ImaginaryHuman(Posted 2008) [#151]
Does DetachThread close the thread completely when it's finished executing its function? Or do I need to call CloseThread at some point?


foosh(Posted 2008) [#152]
EDIT: D'oh, forgot to check "threaded build"

I keep getting errors whenever trying to compile any of the examples found:

Compile Error: Identifier 'CreateMutex' not found

I've rebuilt all the mods using -a -h, built the IDE from the SVN dev repository, what else am I missing?


ImaginaryHuman(Posted 2008) [#153]
AllocThreadData() has to be used like:

handle:Int=AllocThreadData()
SetThreadData(handle,obj)
obj=GetThreadData(handle)

Which is all okay, except this means you have to know the handle of the storage area in order to access the local storage area. You can't just store an object at like handle 0. And since you need something *outside of* local thread storage to tell you where IN the local thread storage to look to get your local data, it sort of defeats the purpose?

For me personally it means I cannot store a custom TThread type in TLS because the handle to the storage area has to be kept outside somewhere, and if I put it in a Field in the type this now means I have to pass that to all functions instead of functions being able to selectively call GetThreadData, which defeats the ability of using GetThreadData to read thread-specific data. I want to be able to store the TThread type instance within the TLS and access different instances of that from each thread, using the same code for each thread. Can't be done. If I have to pass the handle to the type or the handle to the thread storage, there is no point using TLS.

[Edit]Potential workaround??? ... if AllocThreadData() always returns the same value the *first* time it is called within a thread (which it appears to, at least for me), I could put that value in a Global and have every thread use that global as its handle to the local store, to be able to pull up the type instance local to the thread??? How predictable is that?[/edit][edit2]Nope, it's different for each thread[/edit2]

I think it could be done if thread storage was a stack and you push and pop objects to/from it, then I would know that if i push one value and pop it once (or read it without removing it), I could make this work?


JoJo(Posted 2008) [#154]
@foosh

see topic
http://www.blitzbasic.com/Community/posts.php?topic=80696#908121


foosh(Posted 2008) [#155]
thanks!