Purpose of cooperative multi-tasking

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Purpose of cooperative multi-tasking

      First post here and want for start by saying that Game Coding Complete is a fantastic book.

      My question is about the "Process" system in GCC. I understand the basic theory behind cooperative multi-tasking, how you round-robin style cycle through a list of tasks and update them in discrete time increments. Cooperative multi-tasking clearly has advantages on the Operating system level where there are dozens of processes running simultaneously by creating the illusion of simultaneous execution for you programs.

      Why though does is it useful in the game-loop? Say I have three processes, A, B, and C that take x, y, and z milliseconds to iterate during an update function call. Why do I care if they execute linearly or round-robin style? Either way they will complete in x+y+z milliseconds.

      Can someone give an example where cooperative multi-tasking offers a solid, measurable/demonstrable advantage?

    • Well first off, their are a lot of things that should be done linearly, but some things, especially game play elements can be made much more easily done with the process system, here is some examples I have recently used them for.

      A Dialog box process that fades in a dialog box for my story, enters the text in sequentially, then quickly fades out and back in to show the next dialog box.

      Particle Effects, this definitely could be done other ways, but I chose to utilize the process system for my Particle FX, it makes sense as it is a job that happens over multiple frames, has a lifetime.

      Sound Effects, this is the same as the book shows, you definitely could just have a fire and forget system, but it is hard to keep a handle on your sound that way, with a process wrapping the sound effect, it allows you to hold onto a handle, and modify the sound or kill it whenever you want.

      Possibly resource loading, sure you could do it in an extra thread, but I am trying not to over complicate my game, so possibly a list of resources that are loaded one at a time with the process manager could work. Why not just do it sequentially as well? For a small game like mine it would work, it takes at most 1 second to load the resources, if it were a loading screen though it would show a loading image, freeze while loading the resources, then continue on, if your player has a "Dirtbag" as the book calls it, maybe the loading will take 5 seconds, for those 5 seconds of staring at a static screen, that could be one extra thing that makes your game feel poorly done.

      There are many different things to use the process manager for, and you will know it when you come to a problem that requires it.
      PC - Custom Built
      CPU: 3rd Gen. Intel i7 3770 3.4Ghz
      GPU: ATI Radeon HD 7959 3GB
      RAM: 16GB

      Laptop - Alienware M17x
      CPU: 3rd Gen. Intel i7 - Ivy Bridge
      GPU: NVIDIA GeForce GTX 660M - 2GB GDDR5
      RAM: 8GB Dual Channel DDR3 @ 1600mhz
    • Hey electrohamster,

      mholley gives some good examples of sequential processes where the order is important. However this ordering would be enforced by each process having a NextProcess member that sets up a chain. Individually, I don't think processes should be order dependent because you can't guarantee the order they'll be added/executed in without coupling them, and if you're coupling them, then they aren't really separate processes :)

    • RE: Purpose of cooperative multi-tasking

      The Process system is designed to execute actions over multiple "frames" or passes through the game loop - with an incremental change in some value, like a position or scale or volume, each frame.

      When any game object "snaps" it appears to the player as a lack of polish or worse, confusing. Processes are a way to easily code actions that begin, loop, and finish over many seconds.

      Even better, a process may launch other processes, creating a chain. The alternative to this system tends to be a complicated state machine, which can be messy to code and worse to debug.
      Author, Programmer, Brewer, Patriot
    • Sorry to resurrect this thread, but I thought it was better than creating a new one for a similar question.

      In the book, cooperative multitasking was described as being efficient while avoiding the problems with having different threads for parallel execution. Why is it efficient? Wouldn't this be equivalent (speed-wise) to running everything in a linear manner, so wouldn't running things on different threads still be faster?
    • Threads have overhead, especially when locking and ESPECIALLY when a thread tries to access a locked section. Take the classic threading example of have a single global variable that one thread increments and one thread decrements. In order to make this work, you need to surround the increment/decrement code in a critical section:

      Source Code

      1. int g_var = 0;
      2. void AddToVar(int val)
      3. {
      4. EnterCriticalSection(pCriticalSection);
      5. g_var += val;
      6. ExitCriticalSection(pCriticalSection);
      7. }
      8. void Thread1()
      9. {
      10. while (true)
      11. {
      12. AddToVar(1);
      13. }
      14. }
      15. void Thread2()
      16. {
      17. while (true)
      18. {
      19. AddToVar(-1);
      20. }
      21. }
      Display All

      This is a pretty classic example showing how critical sections work. If thread #2 tries to call AddToVar() while thread #1 is inside, it will lock. This will probably happen quite a bit. In this case, making two processes that update would be faster because it's not dealing with the overhead of locking. Threads themselves also have a bit of overhead; just switching to another thread is not particularly cheap.

      This is an extreme example of course and it serves to highlight a really bad case. Let me give you another example, this one from an actual game.

      On The Sims 4, every sim is effectively running its own thread. This thread is responsible for executing the atomic primitives that make up an interaction. Those primitives can do just about anything, including alter gamestate. If they were real threads, it would be a complete nightmare to manage and would run a hell of a lot slower because of all critical sections, semaphores, and other multi-threading tools we'd have to use. It would also be a LOT more buggy.

      Furthermore, I doubt our target min spec machine could even handle that many real threads. We could have dozens of sims on the screen. The Sims Medieval had a similar system and could have over 100. It just wouldn't work to make these real threads.

      So what are real threads good for? The most common task I see threads used for is when the CPU has a lot of sleeping to do. For example, it's very common to put the rendering code in its own thread. The CPU doesn't have a huge amount to do there and will happily pass off its time to the logic thread while the GPU does its thing. The resource manager is another great candidate since it will spend a large amount of its time waiting for the hard drive. These are systems I highly recommend moving into their own thread because the benefits far outweigh the consequences. even better, if you architect them correctly, there is very little locking.

      For example, in my own engine, my render thread is rendering whatever was built up last frame. Basically, the logic thread adds render command objects to a queue. At the beginning of the next frame, there's a sync event where the render thread swaps buffers. Then it spends that frame rendering whatever is in there and waits for the next sync event to get the next set of commands.

      Another thing threads can do is run stuff truly in parallel, as long as you're running on a multi-core processor. This makes them nice long, processor-intensive tasks that can be handed off. Pathfinding is one I see a lot, but only on games where pathfinding is a huge task (like RTS games).

      There are trade-offs no matter what you use. In general, threads are better if you're running on a multi-core system or you're doing something that'll cause the CPU to sleep and you can architect the task in such a way that you have little or no locks (mutexes, critical sections etc.). A cooperative multitasking system is better if you need to change a lot of gamestate and don't want to deal with all the locking, race conditions, and other annoyances that can happen. They're faster if the thread version has a lot of locks.

      Hope that answers your question!