Sign in to follow this  
ibiza420

How many threads for a game?

Recommended Posts

ibiza420    122
Hi all, I am fairly new at developing games (for fun), but not at programming. I am attempting to make a simple demo in C# for a game I may (or may never) code in DirectX one day. For now, I am only using GDI+ to toy around with functionalities such as timing, objects managment, etc. My question is : how many threads a game really needs? I mean by that, that if a game has a single thread, used to generate game objects and to animate the scene as well, what will happen if there is a big lag? My guess is that not only the graphics will lag, but also the object creation engine, which may skip a few objects (enemies, gun shots, etc.) to create (probably resulting in an easier gameplay as not all objects that should be there aren't?). So is there a need to have 2 threads? One for object creation, which should be as fast and accurate as possible, and another one for animation, whose running speed depends on the framerate wanted? Thanks for helping me! ibiza

Share this post


Link to post
Share on other sites
Rebooted    612
Lagging won't cause objects to not be created, just for them to be created in a longer space of time. The frames per second will decrease, but those frames will be the same.

You shouldn't need to use any threading at all. It is only important to people creating next generation games and technology that will take advantage of multi core CPUs. It can also be used to simpilfy code in some cases, but generally you should avoid threading and all the headaches that come with it unless you need to. C# is not a good language for concurrent programming.

Share this post


Link to post
Share on other sites
ibiza420    122
Hi, thanks for your reply!

Well, a program is a thread, that's what I meant with a single thread...no thread at all if you prefer.

But in my case, I have a simple program where I can adjust the refresh rate of my main loop (which handles both the object creation AND the animation), with the help of a slider. I have a "Shot generator" whichs generates simple circles for now, each one with the same constant speed and direction The interval at which these circles are generated is also constant : one every 100ms (or 10 / second). What happens when I decrease the frame rate to less than 10fps (let's say 5), is that there are no more 10 circles per second generated, but rather 5. And it's normal, sinces the loop is only executed every 200ms when the framerate is at 5.

So what would be the solution in my case to still generate 10 circles per second, but update their position only at every 200ms?

This is the problem I am actually facing...

thanks! :)

Share this post


Link to post
Share on other sites
Rebooted    612
Well multithreading could be useful in this situation. Lots of beginners think they need seperate threads for everything, so thats why I suggested not to bother.

If your frame rate drops to 5 FPS then you have big problems anyway, and if it high enough you should be able to use timing code in your main loop to decide when to perform certain actions.

If you can do it in a reasonable way without threading, do it, but you don't have to rule threading out either.

If you do use multiple threads, you have to be very careful about shared state (variables accessed by both threads). Try to keep shared state to a minimum, and be very careful to lock access to variables you do share between threads.

You are in a better position than C++ programmers, but C# still has poor support for concurrency. It does have the lock construct though, and probably higher level constructs in the .NET libraries (I'm not a .NET expert at all).

Share this post


Link to post
Share on other sites
ibiza420    122
Thank you very much.

What do you mean by "using timing code in your main loop to decide when to perform certain actions"?

In fact, I was wondering how professionally-made games were handling the issue I am facing? A game can for sure drop to low-levels FPS like 5/second, even for only a fraction of second, and object creation is still not altered.

Of course, I'd prefer to use a single thread for object creation and animation, but is there a way to correct my problem without splitting animation and object creation in two distinct threads? If so, I'd like to hear it, before trying to do a multi-threading game...it would be sure much simpler.

Share this post


Link to post
Share on other sites
Rebooted    612
Well your main loop executes once per frame, so if you want to do something based on time rather than frames you have to calculate how much time has passed. In your main loop you would do all your normal work for this frame, test if 100ms has passed since you last created a circle, and if it has, create one.

If you used a seperate thread, you'd still have to use this time checking code, but the circle creation would not lag while the rendering thread slowed down. But still, if you can't see the circles that are being created, does it really matter anyway?

Share this post


Link to post
Share on other sites
ibiza420    122
Ok, thanks a lot for your help.

But if I develop a game where timing is vital (I don't know if you know "Ikaruga" :P ), does the discussion we just had means that the game probably has a distinct thread for animation and another one for object handling?

I mean, a game like that cannot afford to "presume" that the FPS will always be the same, and top notch.

In other words, if I want to be 100% sure that every time I run the game, whatever the FPS may be during the gameplay, if I want my objects/ennemies always created *exactly* at the same timing, every time, I do not have choice to have two threads? Because with only one, any lag causes a delay, as minimal as it may be, and affets the timing of the game...

Am I correct?

Share this post


Link to post
Share on other sites
Spoonbender    1258
What makes you think timing won't be an issue with multiple threads?
Threads can be blocked, and they may be executed more or less frequently than you expect.

I really don't see your point about "skipping" object creation. If you use a single thread, then everything will happen sequentially. If you want to create 25 objects, they're created before anything else happens. It sounds more like something I'd expect to happen in a (clumsily implemented) multithreading scenario.

If you want to ensure that everything is done at some specific time, look into fixed timesteps. The idea is to run the game logic in fixed intervals, independent of framerate. That's more or less the only way to ensure that everything happens at the speed you want. And no threading is required.

Share this post


Link to post
Share on other sites
Rebooted    612
Yes, I know Ikaruga [grin]. A game like that is going to have a lot of slowdown, obviously. I'm not sure how the game was coded, Treasure have a reputation for using all sorts techniques.

Spoonbender is right. His comment about everything happening sequentially is what I was trying to get at earlier. Everything that happens in a frame will still happen, just slower.

Splitting the object creation off into another thread isn't going to solve anything. If the rendering thread slows to a crawl, it won't matter that objects are still being created, in fact it will make the situation worse. You won't be able to see the enemies that are spawning anyway, because they arn't being drawn, they are just taking up more resources that you are already low on.

Share this post


Link to post
Share on other sites
JohnBolton    1372
Take a look at this code. It shows how to lock a game at a specific rate regardless of the frame rate:

int const SIMULATION_INTERVAL = 100; // 10 updates per second

while( !game_over )
{
static int last_time = get_time();

int current_time = get_time();

while ( current_time - last_time >= SIMULATION_INTERVAL )
{
update_simulation();
last_time += SIMULATION_INTERVAL;
}

render();
}

Share this post


Link to post
Share on other sites
ibiza420    122
Spoonbender :
My point of skipping the object creation would only appear at extremely low FPS, but I'd prefer to consider it *could* happen, rather than thinking the FPS will always be at top speed.

What I was trying to explain, is that if the FPS drops below the object creation rate (e.g.: the FPS drops to 5 FPS and one "circle generator" generates 10 circles / second), then it will certainly ommit to create one circle out of 2. This would result as not as many objects as expected on screen. Normally, I should only expect choppy graphics, without the behaviour of my objects being affected...

Could you tell me more about "fixed timesteps"? It seems an interesting avenue, but I am wondering how it differs from "standard" implementation of an animation loop.

Thanks for your comment!

Share this post


Link to post
Share on other sites
Frequency    442
Quote:
Original post by ibiza420
What I was trying to explain, is that if the FPS drops below the object creation rate (e.g.: the FPS drops to 5 FPS and one "circle generator" generates 10 circles / second), then it will certainly ommit to create one circle out of 2. This would result as not as many objects as expected on screen. Normally, I should only expect choppy graphics, without the behaviour of my objects being affected...

Not so - the idea is that you write you code such that if you want to generate a circle every 100 milliseconds and 200 milliseconds have passed (5 fps), your program generates two circles. Because it is completely time dependent, it doesn't really matter how many frames per second you have (except in extreme cases like < 10-20 FPS, where it will seem somewhat choppy, but there's nothing to do about that) because the program will just check to see if it's time to deploy a circle yet. 500 fps will be smoother, but the same number of circles will be shown at 5 fps too.

Share this post


Link to post
Share on other sites
ibiza420    122
Quote:
Original post by JohnBolton
Take a look at this code. It shows how to lock a game at a specific rate regardless of the frame rate:

int const SIMULATION_INTERVAL = 100; // 10 updates per second

while( !game_over )
{
static int last_time = get_time();

int current_time = get_time();

while ( current_time - last_time >= SIMULATION_INTERVAL )
{
update_simulation();
last_time += SIMULATION_INTERVAL;
}

render();
}


Isn't there a bug in the code? You set last_time to get_time(), then current_time to get_time() also, and you substract them to check if it is >= SIMULATION_INTERVAL...wouldn't the substraction always result in 0?

Share this post


Link to post
Share on other sites
ibiza420    122
Quote:
Original post by Frequency
the idea is that you write you code such that if you want to generate a circle every 100 milliseconds and 200 milliseconds have passed (5 fps), your program generates two circles.


But even if I generate 2 circles, as they are generated at the same time, they would be one over one...which ends up in one circle on the screen?

And how could I implement it so it actually knows how many circles to generate? The way I did it right now is simply to "check if it is time to generate a circle" (aka: has the delayed expired?), as long as the time diff is > 100ms, I generate one and reset the delay. I don't check if it's > 200ms, then generate 2, > 300ms, generate 3 and so on...

Share this post


Link to post
Share on other sites
Frequency    442
Quote:

And how could I implement it so it actually knows how many circles to generate? The way I did it right now is simply to "check if it is time to generate a circle" (aka: has the delayed expired?), as long as the time diff is > 100ms, I generate one and reset the delay. I don't check if it's > 200ms, then generate 2, > 300ms, generate 3 and so on...

John Bolton already had something like this in his code, but it'd be something like this:

// just pretend, ok?
time_passed_since_last_frame = 350;

while (time_passed_since_last_frame >= 100)
{
do_neat_frame_stuff();
time_passed_since_last_frame = time_passed_since_last_frame - 100;
}

If the delta time was 350, the frame code would be run three times.

Anyway, the main "problem" you're seeing is that the computer is taking 200ms to run a frame of your program - frankly, if that's happening, you are probably doing something seriously wrong and patching that up will fix the problem. In the normal case you will not be running your code once to make up for two frames...you will probably be idling a lot if you go the fixed-frame-rate route, as the PC will just be checking to see if 100 ms (or whatever) has passed yet.

Share this post


Link to post
Share on other sites
JohnBolton    1372
Quote:
Original post by ibiza420
Isn't there a bug in the code? You set last_time to get_time(), then current_time to get_time() also, and you substract them to check if it is >= SIMULATION_INTERVAL...wouldn't the substraction always result in 0?

No. Because the variable is static, the initialization is only done once. You can do it like this too:
    ...
int last_time = get_time();
while( !game_over )
{
int current_time = get_time();
...
}


Also, it might be a good idea to set the initial value of last_time to get_time() - SIMULATION_INTERVAL; to ensure that at least one simulation step is done before rendering.

Share this post


Link to post
Share on other sites
anonuser    148
Maybe no matter what you do you're going to face challenges eithe way.

Me personally I thread my games. Render is on its on thread while an input layer is in its own thread. Sounds are either fire and forget, or synced with the enviornment. This has is ups and downs.

The major down is obviously thread synchronization. Which can be a pain but synchronization quickly becomes second nature.

I like doing things this way. In code you can create really obvious layers and keep things really abstract and easy to work with.

I hope this helps. I am a multithreaded game programmer ;D

Actually I'm just not scared of threads and have been using them for a good while. A lot of people get scared and think its unneeded complexity. And that may be true for some people. The hardest part is learning to design things with threads in mind. Procedural designs just don't cut it as they have in the past.

And C# is an amazing language for concurrent programming! It comes with a pre-allocated thread pool waiting for a task. In essecence all C# programs are multithreaded even the single threaded programs.

Its incredibly easy to create and manage thread in C#. And if you ever go to Win32 its not that bad either. Win32 gives a really great threading model.

Share this post


Link to post
Share on other sites
Rebooted    612
Quote:
Original post by anonuser
And C# is an amazing language for concurrent programming!

No, its really not.

Multithreading is very tricky, and C# in its current form won't be able to cope with the amount of parallelism we are going to be using in the near future, as CPUs get more and more cores.

Explicitly locking access to shared state is incredibly brittle.

Languages that are amazing at this include Erlang, E and Alice ML. Here there is no chance of dead lock or race conditions, parallelizing code is trivial and you are not faced with a debugging nightmare.

Share this post


Link to post
Share on other sites
Spoonbender    1258
Quote:
Original post by anonuser
And C# is an amazing language for concurrent programming! It comes with a pre-allocated thread pool waiting for a task. In essecence all C# programs are multithreaded even the single threaded programs.

Compared to C++, yes. But no, it's not amazing for concurrent programming. There are far better languages for that task.

Share this post


Link to post
Share on other sites
Overseer    162
The problem with using threads is that you either loose a lot of that control that is inherent in sequential code execution, like not having to worry about two elements being added to a list at the same time, and not having to worry about the graphic context for something being updated a split milisecond after that very same thing has already been destroyed, and deallocated its graphic context. You loose the control, OR you loose cycles trying to make sure you keep the control [with memory locking and so forth]. The only real times it is useful are, as was previously stated, networking, or really any completely disjoint systems, that may cause massive slow-down. It is nice for networking in the case of a user sending garbage through the line, so the entire game doesn't just halt while you try to make sense out of gibberish sent from a client. But even then, great effort must be taken to either assure that the memory is always locked correctly, or the communication between the components must be deterministic. [look at your code, and just consider the worst place for it to change threads, and that is the place it eventually will change threads, given enough time. Personally like the mid-insertion problems the best].... this is coming from a bitter C [not c++, though i am spreading into that in recent years] programmer though.

It tends to run fastest, if you maintain control of everything correctly, to do everything linearly. In the case of expensive things like pathfinding, tell your path manager to only expand X many nodes per call, and just remember what it was doing. Unit creation though shouldn't be that taxing, so long as it is at least reasonably organized. Only real instance of things being created getting to be really expensive is some of those particle generators, which will truely suck up every bit of time and memory you allow them to.


Threads can be great though, so long as you use them responsably and prepare for whatever faults they may cause, or you keep the systems that they interact with truely disjoint in operation.

Share this post


Link to post
Share on other sites
Alpha_ProgDes    6936
Quote:
Original post by Spoonbender
Quote:
Original post by anonuser
And C# is an amazing language for concurrent programming! It comes with a pre-allocated thread pool waiting for a task. In essecence all C# programs are multithreaded even the single threaded programs.

Compared to C++, yes. But no, it's not amazing for concurrent programming. There are far better languages for that task.

Out of curiosity, such as?

Share this post


Link to post
Share on other sites
Rebooted    612
Quote:
Original post by Alpha_ProgDes
Quote:
There are far better languages for that task.

Out of curiosity, such as?

The ones I mentioned... [smile]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this