Skip to main content
gamedev.net
🔒 Locked

multi threading

Started by MelloRed Oct 24, 2007 at 7:44 AM 6 replies 1.3k views
Original Post
MelloRed
MelloRed
This is my first attempt at multithreading so i'm unfamiliar. I'm using SDL threads, and i'm trying to do something like. //A,B,C are global SDL_Thread * threadA; do { threadA = SDL_CreateThread(Calc_A(),NULL); Calc_B(); SDL_WaitThread(threadA); C = A+B; } while(!(C.isdone())) This works fine, however creating a thread each time seems wasteful. I'm sure there's are better ways to do this. Any suggestions or advice on how to use threads would be appreciated.
kauna
kauna
Hello,

I don't see the point of your program, unless Calc_A() and Calc_B() do something really complex stuff and you happen to have a multicore cpu. Still, since the C variable is dependant on A and B, this isn't very efficient.

You should create several worker threads that calculate A,B and C in one thread to maximize efficiency.

WorkerThread::Run()
{
C = Calc_A() + Calc_B();
}

You are right that creating a new thread in every iteration is a bit wasteful.
Can you describe what this program a bit more in detail : what do the Calc_A/B do and what kind of variable A,B and C is ?

Otherwise using threads is useful in:

- Streaming (audio, gamedata, video, any media ...)
- Networking code
- Artificial Intelligence
- Loading data
MelloRed
MelloRed
yes, calc_A, and calc_B are complex. and yes i'm trying to take advantage of multi-core, every thing's already setup and running fine on a single thread.
I didn't want to complicate it by adding in the rest of it, but just to show the crux of my problem, but to expand a bit...

do
{
threadA = SDL_CreateThread(Calc_GameStuff(),NULL);
Calc_GraphicsStuff();
SDL_WaitThread(threadA);
Frame = GameStuff+GraphicsStuff;
Draw(Frame);
} while(!quit)
kauna
kauna

Ok, I got the point. Definetely you should not be creating new threads in every frame.

So, you are after of putting rending and game logics in separate threads. That's is a bit more complicated than it seems.

First of all, which may not seem a problem or doesn't show up anywhere (yet):
Have you made sure that Calc_GraphicsStuff() and Calc_GameStuff() don't access and/or modify the same data in the same time ? You might end up in deadlocks/very strange undebuggable bugs.

Here is some information on multithreading a graphics API


Practically, having threads to wait for other threads to complete is inefficient.

So consider your code to do something like :

threadA = SDL_CreateThread(GameThread,NULL);do{Calc_GraphicsStuff(); //use interpolation for smooth animationFrame = GameStuff+GraphicsStuff;Draw(Frame);} while(!quit)MyGame::GameThread(){while(!quit){   every 1/30 sec Calc_GameStuff();}}


The threadA should be make run as long as the game ends instead of just running one iteration. Also threadA needs to keep track of engine frame steps (limit the game logic iterations to 30fps).

Then, either you make sure that game isn't updating its logics you can continue to Calc_GraphicsStuff() (which makes multithreading useless)

or

Have separated data trees for graphical stuff and game stuff and use thread safe queues for updating the object locations etc.


I would start multithreaded programming from some simpler task (like the link I provided).

Good luck !
janta
janta
I don't know SDL threads specifically but usually, you create a thread that will run forever till the end of the program, feeding it with work to do whenever you need to. Very simple example, themain thread can push instances of a class with a Main() method and the secondary thread could op those instances and call the Main() method.

... then synchronization issue will arise [smile]
Good luck!
MelloRed
MelloRed
kauna, you example won't work because you could be in the middle of Calc_GameStuff() when Frame = GameStuff+GraphicsStuff; is switched to. That's why i have WaitThread there, to make sure GameStuff is done before it's combined. I need a device to stop the thread, and make sure it runs at least once (though more then once per frame seems a waste).

After a bit more research I've come up with this solution, but i still don't think it's the best.

Calc_GameStuff(){while(!quit){SDL_LockMutex(gamestuff)//gamestuffSDL_UnlockMutex(gamestuff)}}threadA = SDL_CreateThread(GameThread,NULL);do{Calc_GraphicsStuff();SDL_LockMutex(gamestuff)Frame = GameStuff+GraphicsStuff;Draw(Frame);SDL_UnlockMutex(gamestuff)} while(!quit)


This would prevent lockups and insure integrity but doesn't mean that Calc_GameStuff() will run once a frame, it could be called more which is a waste, or not at all (though that's unlikely)
MelloRed
MelloRed
ok i think i figured it out
SDL_cond* gamestuff = SDL_CreateCond();SDL_mutex* framestuff = SDL_CreateMutex();Calc_GameStuff(){ SDL_LockMutex(framestuff) //CondWait must have a locked mutex while (!quit) {  SDL_CondWait(gamestuff, framestuff);  //unlock framestuff, wait, then lock framestuff  //calc }}SDL_Thread threadA = SDL_CreateThread(Calc_GameStuff,NULL)do{SDL_CondSignal(gamestuff);  //start the gamestuff loopCalc_GraphicsStuff();SDL_Lock(framestuff);   //wait for the gamestuff loopSDL_Unlock(framestuff); //reset the gamestuff loopFrame = GameStuff+GraphicsStuff;Draw(Frame);} while(!quit)


can anyone see any problems with this?
the_edd
the_edd
You might find my async library useful (free for any use). It's for exactly this kind of thing (I'll assume you have a valid use case).

Your code would look like:

async::future<Type_of_A> fut = async::call(cage, Calc_A); // Call Calc_A asynchronouslyB = Calc_B();C = fut.value() + B; // waits for Calc_A to generate a value, if it hasn't already


In the above, cage is an object that handles exceptions from child threads.

The library is built on top of the boost thread library. Threads are added to a pool and re-used by subsequent invocations of async::call().

There are overloads of async::call() that take arguments, too, and a bunch of other related stuff.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.