I've thought of a very simple way to distribute worldgen across multiple threads. Simply generate separate worlds on each thread.
This works because worldgen typically produces perhaps 60 rejects. With a single thread, that means 60 rejects, then a proper world. With two threads running worldgen, each thread likely only ends up with 30 rejects before one or the other produces a non-rejected world (still 60 rejects total, but split up between the threads). With three threads, only 20 rejects, four would have around 15 each, and so forth. Each thread simply generates worlds, and we pick whichever one passes the rejection tests first.
Basically, the process works like this:
Mainthread spawns several worldgen threads.
Each worldgen thread has its own RNG seed, and runs in a separate memory space. No interaction with the other worldgen threads.
When one of the threads produces a world that passes the rejection tests, it writes its index to a global int slot and goes into idle. This is completely thread safe since because writing an integer is an atomic operation (make sure #pragma pack 4 is on, so there's no chance that the global integer strides a 4 byte boundary! Your compiler most likely makes sure of this anyway, though... It also needs to have the volatile keyword), also, if another thread happens to also write its index over it, it's only because it also has finished a good world. Thus, it doesn't matter, since either way we have a good world.
Meanwhile, the main thread periodically checks the global index word to see if it's been changed by a finished thread (make sure that the index is volatile - i.e.
code:
volatile int index = -1;
). Once it sees a index to one of the threads, it kills all the other threads, and reads back the finished world from the indexed thread.Now the main thread just goes on as normal.
The nice thing about this approach is that it requires very little code change. Simply bind the worldgen function to a thread pointer, ensure that it creates its own set of working variables, and it's good to go!
The only other things to watch out for are displaying the world in progress (since there's only one screen to display to! Ah well, I guess we'll have to pick just one thread to display), and readback of the finished world (which might not be a concern if we use invoke() from the main thread to make the finisher thread save the world to disc, export bitmaps, and so forth until we return to the main menu)
[ April 23, 2008: Message edited by: Keldor ]