Quick question about multithreading...[solved]

Started by
17 comments, last by Moe 18 years, 8 months ago
Hey all, I have been doing a little thinking about all this new fandangled multithreading, and I figure that the application that I would like to write can benefit from it. I was thinking of one particular instance where multithreading might come in handing: the loading screen.... After having seen the original serious sam, and how they had a loading screen that was animated, I have thought it would be cool to do something similar (for those of you who haven't seen it, they had two textures scrolling over eachother to make it look like rolling clouds, but tinted green. It wasn't anything super-technical, but it looked cool). I have been doing a little thinking on how I can do something similar. I was thinking that I could use the primary thread to render the animated loading screen while using a second thread to do the loading of the game files (levels, textures, etc). This way I would be able to update the animated loading screen without having to wait for each asset to be loaded, as it wouldn't be on the same thread. This way I think I could get a decently smooth animation going, yet still load in the game files, one file at a time. How hard would it be to implement something like this? (Is it even possible?) Do any of you have any handy resources for learning about multithreaded programming? [Edited by - Moe on August 17, 2005 5:52:49 PM]
Advertisement
Well, I'm not sure that multithreading is "new fandangled" as it's been used in games in one form or another for a very long time. Even Windows 95 had OS support for threads. In any case, sure you could do a loading screen with multithreading. I probably wouldn't, but that's just me.

Threads are very commonly used for asynchronous disk accesses, and some people do network stuff in a separate thread.


I was thinking that it would be nifty to use it, as it would prevent the rendering loop from being held up by waiting for the load() method to return after an asset is loaded. The more I think about it, the better this sounds to me. Of course there might be a little stuttering because of the HDD access, but that is acceptable.
Threading is trivial in cases where the two threads don't share access to any variables (which it seems like would be the case here). It gets more complicated if they have to interact in some way.
Thats what I have heard. I figured it wouldn't be all that bad because its not like one thread is relying on the other thread to do something. Now I guess I just have to find some resources on doing multithreaded programming....
See that's why I wouldn't use it for the loading screen, because I would already be using multithreading for the loading. Same thing only backwards.

If your engine has the rendering in the main loop, it might be easier to put the loading screen in the main loop, sending IO requests to another thread and checking on the status of them as they load then update the loading screen.

I think most engines have the rendering/user input loops in the main loop and async IO in a seperate thread. I do know that there are some things you can not do directly in Win32 if you're not in the same thread as the one where you created the application window.







Vanilla MSDN threads reference
Various posts on my blog about thread synchronization topics.
While we're doing linkfu, if you're going to use threads, I would highly suggest the Boost C++ Libraries, specifically in this case Boost.Threads

A quick google search of my posts on GD.Net brought up this very basic example I gave in another thread, and although I recall making a better one, I did not find it.

#include <boost/thread.hpp>#include <boost/function.hpp>#include <iostream>#include <windows.h> //for Sleep X.xusing namespace std;void foo( void ) {    cout << "Hello world" << endl;}void delay_foo( void ) {    Sleep( 3000 ); //3 seconds    foo();}int main() {    boost::thread run_delay_foo( &delay_foo ); //starts a new thread of execution running delay_foo()    Sleep( 6000 ); //6 seconds}


The above program should say "Hello world" 3 seconds into it's execution, then quit after another 3 seconds.


So far this example dosn't seem much better than any C based thread library. The main beauty IMO is the use of boost::function to facilitate type safe argument passing to the thread's function. The above example slightly modified to illustrate what I mean:

#include <boost/thread.hpp>#include <boost/function.hpp>#include <boost/bind.hpp>#include <iostream>#include <string>#include <windows.h> //for Sleep X.xusing namespace std;void hello( const std::string & greetee ) {    cout << "Hello, " << greetee << endl;}void delay_hello( const std::string & greetee ) {    Sleep( 3000 ); //3 seconds    hello( greetee );}int main() {    boost::thread run_delay_greeting( boost::bind( &delay_hello , "World" ) );    if ( rand() % 1 ) {        Sleep( 6000 ); //wait 6 seconds as the thread runs seperately    } else {        run_delay_greeting.join(); //wait for the thread to finish (3 seconds)..        sleep( 3000 ); //...then wait another 3 seconds.    }}


Note that a temporary of type std::string will automatically be constructed from the C-style string "World", instead of as with most thread libraries with equivilant code, crashing as a raw pointer is interpreted as a type it is not and attempted to be used.

EDIT: Example expanded to show how to wait on a thread with join()
Wow, thanks for the resources! That ought to keep me busy for a little while. One last question: Is there an optimal number of threads to use, or is that processor dependant? For example, I am running a P4 3.4Ghz/HT, which to my understanding, can handle two simultaneous threads at a time. A dual-core processor of the same type should be able to handle 4 threads simultaneously, right? How many threads is it generally safe to use?
The ideal number of running threads per core is 1, or 2 for hyperthreading.

This topic is closed to new replies.

Advertisement