Author: Amit Patel
Date: Tue, 12 Aug 1997 14:44:05 -0700 (PDT)
From: Amit Patel <amitp@CS.Stanford.EDU>
Newsgroups: rec.games.programmer
Subject: Re: Win32 Threads and Games
Organization: Computer Science Department, Stanford University.
Status: OR

Michael A. Greenly wrote on rec.games.programmer:
>> Hello,
>> For a game running under Windows 95, what would be the best way to use
>>
>> the Win32 threads?
>
>[snip]
>
>    It seems the popular answer was don't use threads.  If your target
>is Windows 95 it's likly the correct answer, but if your target is
>furthur down the road a multi threaded game engine may be  worth
>considering.
>     Multiple threads allow you to design the game engine in very clean
>modular manner.  In addition I beleive  the performace hit associated
>with high thread counts  has been exagerated.

I think the performance hit depends greatly on the kind of game you have. In my game (which has a lot of calculations on a grid map), there are some things that help me use threads without a big performance hit:

  1. The simulation thread is the only one that modifies the map.
  2. The display thread is NOT bothered if it gets inconsistent information from the map. It will just fix itself the next time through the drawing loop.
  3. The input thread doesn’t directly affect the map, but instead puts requests in a queue which is read by the simulation thread.

Locking data structures is a big source of slowdowns in multithreaded programs. The main data in my game is the map -- but I *don’t* need to lock it! This is because only one thread writes to it, and only one other thread reads from it; the display thread doesn’t depend on consistent information being in the map, so if the simulation thread is in the middle of updating it, it’s OKAY.

The data structure that _does_ need to be locked is the input queue. However, I have some nice properties in my threads:

  1. The simulation thread only READS and CHECKS (for non zero size).
  2. The input thread only WRITES.

I don’t have to lock the queue unless it’s short, since reads and writes are done far away from each other. There aren’t _that_ many input events (mouse clicks, mostly) so locking the queue for reads and writes isn’t a major problem.

There _are_, however, a lot of checks (to see if the queue is empty), but the queue doesn’t have to be locked for this (!): only the simulation thread could possibly decrement the size, so that thread does not have to worry about the queue going to zero size while it’s checking it. (It doesn’t matter if the queue increases in size -- the simulation thread just wants to know if it’s empty or not. Also, it’s OKAY if the simulation thread found a zero size while the size is being incremented -- it’ll just pick it up the next time around the loop.)

I can’t really recommend threads to everyone, but in some cases, threads can work. The main thing to watch for is locking of data structures. If you don’t lock enough, you’ll have HORRENDOUS bugs that disappear every time you try to find them. If you lock too much, your game will be slow. However, if you can arrange your threads and your data so that simultaneous access is tolerated, then you may be able to get good performance without excessive use of locking. Try to make sure that only one thread can write, and make sure that reading inconsistent data is not a problem. Also, make sure that threads work decently on your platform of choice. :-)

- Amit
--
Amit J Patel, Computer Science Department, Stanford University
http://www-cs-students.stanford.edu/~amitp/
   ``Nature is an unsatisfied artist, always carving and molding
     her fabuluous sculpture.''  -- unknown