C++ Thread safety

Started by
23 comments, last by addy914 11 years, 8 months ago
Hello everyone, I am planning on making a game with C++ and I am wanting it to be multi-threaded. The biggest issue with having multiple threads is making it thread-safe. I know of the many ways to make it safe, but I want to know, what will be the BEST and FASTEST for me. My primary question is what's the fastest, but if you want to list off the pros/cons of each one, then hey, I don't mind learning more :P

Basically, I am going to have 4 threads for loading content, one thread for input/output, one thread for rendering, and one thread for networking. I am going to have a Form class to represent the current Form/Screen. This Form class will be the basis of where I need to start worrying about thread-safety. The Form class will have a HandlePacket,Draw, and HandleInput functions that will each be called from different threads. The form will have variables in there that will be accessed from each thread.

I do know that mutexes are slower than windows EnterCriticalSection/LeaveCriticalSection since the critical section is user mode and mutexes are performed at a kernel mode. But, I am not sure if boost's smart pointers are faster than critical sections. I did try out atomics for a bit, but it actually deadlocked a program for no reason at one point. I also heard of having TLS, which could possibly work.

If I were to use smart pointers, would I make the form a smart pointer, or just the data inside of it? If I were to use TLS, the data wont be synchronized per thread, correct? If I were to use EnterCriticalSection/LeaveCriticalSection, would I have a CriticalSection variable for each variable inside the form, or just one for the form?

I am going for a balance between memory and performance effeciency. So, I don't want the option that takes a ton of memory but is fast, and I don't want the option that takes no memory, but is slow. A good balance would be ideal for me.

I would greatly appreciate a pros/cons list of my options because going from website to website, someone seems to say something different. It would help set me straight on what works and what doesn't. Thank you in advance.
Advertisement

My primary question is what's the fastest
Don't share data between threads ;-P
Basically, I am going to have 4 threads for loading content, one thread for input/output, one thread for rendering, and one thread for networking.[/quote]What about on single-core or dual-core CPUs? Thread-pool systems (with a variable number of threads based on the CPU) that are executing a flow-based graph of tasks are generally very simple and efficient.
Haha, I wish I didn't have to share data between the threads, but I do :(

I think I understand what you're saying, and that might just work out. I would still have to synchronize the data, but what you're saying could work better. Well, to think of it, I am using OpenGL to render. I actually have to set the context in the thread to the OpenGL one at initialization. It would be somewhat wasteful to set the context of each thread in the pool.

Haha, I wish I didn't have to share data between the threads, but I do sad.png

I think I understand what you're saying, and that might just work out. I would still have to synchronize the data, but what you're saying could work better. Well, to think of it, I am using OpenGL to render. I actually have to set the context in the thread to the OpenGL one at initialization. It would be somewhat wasteful to set the context of each thread in the pool.

Hodgman is right with his answer.
If data must exist in another thread, make a copy.
I created a messaging system for my own applications to achieve that. In my approach the only thing that gets shared between threads is the message queue. The messages define the information flow in a strict way. So the overall system gets more structure.
I'm not sure if it would even be beneficial to have multiple threads if I use a queue system to get and set data. I could make a copy of it, but still the data needs to be synchronized between all threads to be accurate. The whole Form class is going to be accessed by each thread and the data inside of it. If I make a copy of all of that, that's about 8x the Form class then I need and want :P

I just want one instance of the Form class, and I want it to be able to be safely accessed by all of the threads. I have seen threads about shared_ptr being slow, and I could believe that. I think they overdid it with the shared_ptr. EnterCriticalSection is what I'm leaning towards, but I'm not sure if I should have one critical section for the whole form, or for the variables inside the critical section. Also, what does Linux/Unix offer for thread safety? I did plan on making this project for other OS systems, and if they don't offer something just as fast and simple, then I would be right back to this question.

I'm not sure if it would even be beneficial to have multiple threads if I use a queue system to get and set data. I could make a copy of it, but still the data needs to be synchronized between all threads to be accurate.

A single thread should only rely on the data it has available to a specific time. That works in the following situations.
The threads have different functionality and so are not forced to be absolutly in sync.
If multiple threads are working for the same functionality the data should be split to de-couple/unshare the threads-data.


I just want one instance of the Form class, and I want it to be able to be safely accessed by all of the threads. I have seen threads about shared_ptr being slow, and I could believe that. I think they overdid it with the shared_ptr. EnterCriticalSection is what I'm leaning towards, but I'm not sure if I should have one critical section for the whole form, or for the variables inside the critical section. Also, what does Linux/Unix offer for thread safety? I did plan on making this project for other OS systems, and if they don't offer something just as fast and simple, then I would be right back to this question.
[/quote]
EnterCriticalSection/LeaveCriticalSection are done with a single assembler instruction. If you use something generic access to data is locked at all times. If you do the locking by yourself you can decide for every situation anew, wether access must be locked or not.
Using a mutex is something to be used between multiple processes that share data through a shared-memory-segment. So for threads critical sections are enough.
In linux/unix you find often pthreads that give you the same functions.
If I were to use smart pointers to ensure thread safety, then what would I do for regular variables? Would I just turn that into a variable and deference it when I needed to change it? If I were to use smart pointers and I wrap a smart pointer around a class and each thread accesses that smart pointer at the same time, is the data inside the class thread safe? If all the threads call a function from the smart pointer and that function accesses data inside the class, is it thread-safe?

I still don't have legitimate reasons not to use atomics. They seem like a good idea, but I don't know how efficient they are. Reading about atomics, it seems that it all is based upon your CPU.
Here's a great article that talks about how to make modern multicore game engines. I'm basing my engine on this.

http://software.inte...el-game-engine/

If you look at PhysX and other game engines of today like Rage, Unreal, they talk about doing similar things, just not in as much detail.

I also strongly recommend you use intel thread building blocks if making a PC game, or whatever is available if you're making it on a different platform. I probably wouldn't bother with multithreading a game on a phone just yet though. Maybe give it a few years.

http://threadingbuildingblocks.org/
Yeah, I see how that would work well. How much overhead does smart pointers or critical sections have. It seems like a lot of trouble to have locak copies of all the data if the overhead isn't going to be noticeable. Theoretically thinking about it, the time to lock, exit value, and unlock wouldn't be noticeable. The issue is how much memory critical sections take upup
The point of the intel article was to avoid things like critical sections.
If you have shared data, it's best to pass it around as messages to a bunch of things and have them go forth and do their own thing.

You basically have a bunch of systems running on their own and being synchronized by sending each other messages, and it's best to avoid the number of systems and the number of synchronization that needs to happen since this is a memory and memcpy overhead.

For example, I could have 50 AI characters that need updating. Every game loop I'd tell the AI guys to go off and run in their own worker threads in parallel, (Very easy and takes a few lines if you are using Intel TBB or OpenMP as those manage it all for you). Then at the end of the game loop I'd synchronize all the changes up. Some AI character might be set to observe the position of another AI character so it can make new decisions next update. So i'd have the observee send a copy of its position to the observer so no critical sections or synchronization is required mid game update.

I also was reading the Unreal Engine 3 documentation and each game update is divided into 3. The pre step, the actual step, and the post step. I'm not sure I 100% agree with their method so far but they have the middle step have all actors update in parallel. The pre step and the post step update all actors serially.

This topic is closed to new replies.

Advertisement