Multithreaded game

Started by
6 comments, last by Fallonsnest 15 years, 1 month ago
Im trying to implement some multi threading to my game project but have some questions about it. The main threading system will be splitting the update/render thread so the update thread can do some work (non graphics related) while rendering the scene. Done some reading about multithreading but im still confused about few things. the main plan i been testing at is using events in the render threads. so for example the update thread goes like this: - Wait for 'UpdateFrame' signal - update renderable stuff (call rendermanager functions) - trigger 'RenderFrame' signal - update non renderable stuff so the update thread run in a loop waiting for the UpdateFrame signal every time is start the loop process. The UpdateFrame event is triggered at the end of the render proces. This causes both threads to run at same speed and synconise trough events. This seem to work fine for now. All calls to the render manager will add a new 'command' to a command que that is processed by the render thread (all D3D code happens inside the render thread) Now some other theory i been reading about is not syncronise both threads and work with buffers instead so that would change my update thread to: - update renderable stuff (fill a render command que) - trigger 'SwapRenderBuffer' (render thread copy the render command que) - update non renderable stuff in this case both threads will most likely run at different speeds and that kinda bothers me or make me wonder whats the point of it? lets say the render thread runs at 100 FPS but the update thread only run at 1 FPS (its low, but just to set an example). If the update thread can only update the "render command buffer" once a second and the render thread get a new command que every second ... whats the point of drawing the same frame 100 times? so whats the best solution? syncronize threads like in 1ste method or buffer the threads like in second method?
Advertisement
Quote:In this case both threads will most likely run at different speeds and that kinda bothers me or make me wonder whats the point of it?


I asked a similar question years and years ago on this site. So here are my findings. Multithreading in general is a very nice concept, but only if it is implemented properly. In the case of a game, the implementation of such a thing is very specific because everything is time critical and in some cases, bound ONLY to the main thread. Putting a renderer and the update mechanism on separate threads is generally frowned upon because of several reasons:

- OpenGL, DX9, DX10 (Somewhat) are designed to be run on a single thread. Mutexing the render and resource management calls can get very heavy and may slow down your processing.
- Moving data back and forth from one thread to another requires critical sections and mutexing. This has to be applied to almost all data.
- Some operations are blocking and cannot be threadded because the rendering system is a state machine.

In the case of DX11, it will supply the programmer with enough control that multithreading would be possible. But It is not yet released. DX10 sort of allows mutlithreading but it does not do it perfectly. I vaguely remember reading something about this...

But I feel your pain and I may have a solution for you. What I would suggest is to keep everything on the main thread (rendering, updating, input, etc) and run a Thread Pool. You then would create a bunch of Jobs and plug them into the Thread Pool and wait until they are all done. This will speed up some processing by running Jobs on different cores. I do this for my scene management and I can test several collisions at once. If you are on a Job thread, you obviously want some sort of critical section around the data that you are accessing and writing to. There is a Thread Pool that is built into DX, or you can write your own. You can also run some smaller subsystems on their own threads, such as Sound, Networking, AI, etc. In those cases a thread pool comes in handy as well.

Take a look at my blog post about this. It contains some Benchmarks for you to refer to.
------------Anything prior to 9am should be illegal.
RealMarkP has you pretty much covered, though I will add that unless you are heavily CPU-bound, multi-threading is generally not worth the effort.
Quote:Original post by RealMarkP
I asked a similar question years and years ago on this site.
/offtopic: you make me feel terribly old [wink]

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

The point of threading is to do stuff asynchronously. One possible side effect of this is that it can cause a speed up if it is able to do things at the same time. Another possible side effect is that performance decreases because of resource contention and communication overhead. Some languages like ruby don't support native threads, therefore it is impossible to improve performance by using threads.

When using threads to improve performance there are two things to focus on the first is keeping communication\synchronization overhead low. The second is keeping unneeded work to a minimum. Your first example keeps unneeded work to a minimum but can have a high sync. overhead. The second can do a lot of extra work that doesn't help performance.
RealMarkP, when u talk about using thread pools it make me wonder about 1 thing.
If for example the thread pool has 3 worker threads and all 3 execute a task doing some D3D stuff ... wont that give a problem?

the reasson i wanted to split the render thread is to keep all D3D code in 1 single thread away from the rest of the application.

As for physics im using NVidia PhysX that also run on its own thread.
in the first sample, after the render command que is fill, the render and physics thread run at same time (so updating actor possition and stuff for the next frame)
The physx run on separated threading using its own thread pool for working tasks.

As for the sync overhead, i want to add some setting like the physics sdk where u can choose to use multi or single threading.
Quote:Original post by Fallonsnest
As for physics im using NVidia PhysX that also run on its own thread.
Since PhysX is already running on its own thread, that means you have currently one thread for rendering + book keeping, and one for physics. Unless you have fairly heavy AI computations, or similar, you won't see much benefit from additional threads.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Quote:Original post by Fallonsnest
RealMarkP, when u talk about using thread pools it make me wonder about 1 thing.
If for example the thread pool has 3 worker threads and all 3 execute a task doing some D3D stuff ... wont that give a problem?

Yes, that would cause a problem because you would be modifying a state machine asynchronously, which is a bad thing. What the Thread Pool is designed for is to execute non-render code. For example, finding out what objects are colliding, doing some file IO, etc. Once you touch D3D you get into a whole slew of problems (as mentioned above).

Quote:the reasson i wanted to split the render thread is to keep all D3D code in 1 single thread away from the rest of the application.

Understandable, but you can also do this via patterns. You can separate the rendering code away from your game code by using interfaces. So at any given time, your game code only calls interfaces and not actual D3D code, leaving it clean and easy to read. Alternatively, you can put your code into a DLL which gives it another level of abstraction. Are you doing this for code clarity or structure?

Quote:As for physics im using NVidia PhysX that also run on its own thread.
in the first sample, after the render command que is fill, the render and physics thread run at same time (so updating actor possition and stuff for the next frame) The physx run on separated threading using its own thread pool for working tasks.

I used to work with Novodex, which was the precursor to PhysX. It can be put on a separate thread but you are just making more work for yourself. The way you update the physics engine is by passing it a value that represents the time elapsed since the last time it was called (in milliseconds). This does not merit another thread, rather you can call it at any point in your engine, as long as the value being passed into it is accurate. I bet PhysX actually does its own threading internally to traverse its Octree or similar. Now ask yourself this question: Does updating the Physics engine more times then you render give you any benefits over updating it once per render? (Note that physics engines can interpolate movement to 1 millisecond if they think there is a potential collision).

Quote:As for the sync overhead, i want to add some setting like the physics sdk where u can choose to use multi or single threading.

Actually, if you design a Thread pool well, you can easily accomplish this. Running everything on one thread is essentially the same as running everything on the main thread. Therefore, all you really have to pass into the Thread Pool is the number of threads you are willing to use. The queuing system will take care of the rest (As long as you block on the main thread).

Quote:Original post by swiftcoder
Quote:Original post by Fallonsnest
As for physics im using NVidia PhysX that also run on its own thread.
Since PhysX is already running on its own thread, that means you have currently one thread for rendering + book keeping, and one for physics. Unless you have fairly heavy AI computations, or similar, you won't see much benefit from additional threads.

Switfcoder is right. When you have more threads then Cores, the OS will end up timeslicing the threads. If you read my blog article, I actually mention that for each subsequent thread that is created above the maximum number of cores, the time to compute the task increases due to timeslicing/mutexing. You will always be capped by the number of cores on the CPU which make threading a static number of threads very tricky. If you want to run 3 threads on a machine with 2 cores, you will get as much benefit as running 2 threads on a dual core machine.
------------Anything prior to 9am should be illegal.
Done some more testing on the thread pool and worker tasks yesterday.
It seems i wanted to make my project to complicated by moving rendering to another thread.

Doing all rendering in the mainthread and do all non render stuff trough the thread pool is much easier way to handle stuff.

So basicly i have 3 large threads atm.

Main thread, physics and networking.

So the main thread does all rendering, wich allow to remove the render command que and go back to direct calls on the render system. At the same time the thread pool process tasks such as user input (keyboard/mouse), network input, AI, loading files ...

This topic is closed to new replies.

Advertisement