Avoiding critical sections or shared data access whenever possible is key to successful multithreaded programming. After a recent discussion in another thread here I decided to drop multithreading in my game, but now I have enough good reasons to switch back to it. Anyways, I had the following idea to handle game modes/modules in my game:
1// This class is to be inherited for new game modes
6 // Any shared resources go here
11 // Load shared resources here
14 virtual void Update()
16 // Update game mode logic
19 virtual void Display()
21 // Render game mode
31 if (!gameModeInitialized)
33 gameModeObject = new CGameModeDerivedClass;
34 gameModeInitialized = true;
36 if (gameModeObject != NULL)
43 if (gameModeObject != NULL)
This is a very abstract example, but the idea here is to avoid the necessity of mutexes by making it impossible for the rendering thread to even access any graphics before they're reading. I don't really trust Allegro mutexes, the reason can be seen in this old thread. I don't know if I just used them the wrong way or if they weren't fully functional (and I would love if someone with more experience can clarify), but anyways my question is the following: Does the above idea work? Or in other words: When does the new operator actually return an address? Is it like a function call, which only returns a value once the function itself returns (so in this case after the constructor is done), or does it return an address the moment memory is allocated? In the first case my solution would work because gameModeObject could only become != NULL after all resources are loaded. In the second case Display() could be called without all resources being loaded and therefore cause errors. In this case I would need mutexes.
Now for a second question. I might load my resources in the logic thread (for better resource management and stuff). This, of course, will load them as memory bitmaps, since the display is created by the rendering thread. My question concerns al_clone_bitmap(). I read you can use it to easily convert memory bitmaps into video bitmaps. But how fast is it? We all know that loading graphics from disk is a rather slow process, but al_clone_bitmap() as far as I understand works with memory only, so it should be a rather fast process, am I right? If it's actually pretty slow then I might have to load my resources on the display thread, after all, which would kill one of the purposes I want to switch back to multithreading in the first place. Basically I want to be able to show an animated loading screen witout extreme programming effort. This way I could make the logic thread load resources (which takes quite a while) while the display thread could animate and display a logo or something.
A third thread concerns multithreading on systems with one processor core only. Does anyone know how multiple threads behave on such a system? From what I know each platform has a scheduler which tries to give each thread about the same processor time. This behaviour is mandatory for having my game work the way I want it to (and for benefitting from one of the other reasons I'm switching back to multithreading). If you have read one of my recent threads you probably know that I'm aiming for the following game structure:
Logic thread: Constant FPS (25)
Rendering thread: Variable FPS with interpolation (letting it run through as often as possible or letting VSync dictate the speed)
What I want is that the logic thread, since it has only 25 FPS, can always process all of its frames even on slow hardware, whereas the rendering thread's FPS gets reduced on slow hardware to allow the logic thread to always get the needed CPU power (while on fast hardware the interpolation makes a smooth image possible). However, since I don't really know how to program this kind of speed control optimally I thought I could just let the OS handle everything and for this I need to know how singlecore systems behave. I know that my approach should work on systems with at least two cores, since both threads would always run on different cores. But can I assure that my logic thread always gets the time it needs even on singlecore systems (assuming the OS isn't slowed down by other processes)?
Whew. These questions were definitely hard to word. I hope you always get my point.