Just as a clarification, there are four main AI war threads right?
1. The main thread: The primary thread that runs the main method. It is responsible for maintaining program flow, and controlling and monitoring at a high level the UI (Runs on each machine, but by definition, the stuff it handles only matters to the exact computer, it doesn't need much multi-player synchronization. Managing game state happens in a different thread)
2. The simulation thread: Where the "magic" happens; the main simulation loop. (This is the only thread whose computations must be consistent among all machines in a multi-player environment)
3. The AI thread: As the name would imply, this is the thread that runs the code associated with the AI, effectively allowing the AI to run independantly of the main simulation, just like the player. (Notice that this implies that the AI can abuse pause mode, if the option to allow giving orders during pause is on, just as well as you can. In fact, if I am reading the debugging information right, they do
) (This thread only runs on the host, and only the final orders made by the AI need to be communicated with the other players, which is handled in the simulation thread)
4. The rendering thread: As the name would imply, this is the thread that is responsible for drawing the in-game graphics, including managing graphics tasks to be done by the GPU, if any. (This thread is run by each computer, but becuase other players don't care about exactly what other computers display, it doesn't need to be syncrhonized among clients.)
There may be other threads, like one for sound or one for networking. And of course there are ones spawned by the underlying libraries that we don't care about, as those are implementation details.
The nice thing about this separation is that very little cross-communication needs to happen across these different threads. Sure, one way reads are common, like the graphics thread reading the state of the game managed by the simulation thread so it knows what to draw, the main thread from the simulation thread so it knows what objects to show in dialogs, the AI thread needs to read the game state managed by the simulation thread so it know what the flip is going on with its units, the simulation thread needs to listen for commands advertised by the main thread (which handles UI which is how players give commands) and the AI thread (so the AI can issue orders), and the main thread needs to keep "track" of the other threads so that it knows how to manage them or react to their state changes.
However, these types of communication are rather trivial, and don't really introduce too terribly many synchronization issues. Oh sure, sometimes you can get conditions where a thread tries to read stuff that is not guaranteed to be ready for consumption yet, and thus introduce a race condition, and I think there have been bugs like that before, but for the most part these are pretty easy communication to deal with in both a correct and consistent basis.
Much more difficult are threads that need lots of communication between them, like non-trivially parallelizable tasks. That is where it gets nasty to ensure correctness and consistency.