I considered several programming models for the Space Tyrant server design. The Last Resort (TLR), a predecessor to Space Tyrant (ST), is based on a process-per-user forking model using inetd or xinetd to handle the listening and spawning of new processes. While the forking model is inherently distributable to multiple processors, it introduces inefficiencies such as extra memory usage and it also makes coordinating user activities slow and difficult.
Second, I considered a non-blocking, single threaded, single process model. In this approach, one process handles everything in a single thread. It would use non-blocking IO, where IO functions return immediately if they encounter a would-be delay to their read or write operation. Obviously, the code logic has to keep track of pending IO operations and the user sessions dependent upon them. The thttpd web server is an example of a non-blocking, single process server. It's extremely fast and efficient although it only makes use of a single CPU core. However, this model is quite complicated to code, and might make it easier to introduce timing bugs.
Third, I considered a pure multithreaded, single process model with a thread for each player. While appealing in many ways, this model would require the same kind of coordination between threads that the process-per-user, forking model requires between processes. Such interprocess communication would be slightly simpler than the forking model in that the various threads inherently use the same memory, but the coordination issues otherwise remain the same.
Last, I considered a hybrid threaded model. This model would include IO threads for each user, a disk backup thread, a network listener thread, and a single master thread to implement all game logic and data manipulation. While that central thread might become a bottleneck on multicore systems, it does offload the IO processing, listening, and backup to any additional processors, and, best of all, it requires minimal coordination overhead.
The IO threads would write their requests to queues serviced by the game logic thread, which would send a response to each IO thread as that thread's requests are completed.
The listener thread's job would be to listen for new network connections and to spawn IO threads for each new player connection. The backup thread would periodically scan the game data and write any modified data blocks to disk.
This model combines the game logic simplicity of the non-blocking single process model with the coding simplicity of the threaded model, while separating the IO -- and its associated delays -- from the main logic.
The tradeoffs seemed quite acceptable so this last model was the approach used for the ST project.
The code is written in C to compile with GCC and runs under both Linux and Mac OS X.
No comments:
Post a Comment