Multithreading and Lua scripting
Let's discuss the question "do we need a separate evaluation thread for lua scripting".
Currently scripting (mwscript) works in the same thread as rendering and in most cases doesn't take a lot of time.
Why would we want to run lua in a separate thread?
- Lua scripting will presumably be used by mods very extensively and in the future can become a bottleneck.
- We plan to dehardcode game mechanics and move some code from C++ to local Lua scripts. Lua is slower, so if we run it in the main thread, it will cause visible performance loss.
- In multiplayer mode all communication with the server will likely work in the same thread as local lua scripts. For the best performance it should be separate from the rendering thread.
The main drawback is difficulties with synchronization and concurrent access to the data.
Synchronization and access to the data
Even read access to the world state is not thread safe. For example there will be a problem if one thread reads a value from some std::vector exactly at the same time when another thread adds a new element to the vector, because the vector can decide to reallocate its internal storage and move all elements to the new one.
Locking concurrent access by critical sections doesn't look reasonable here, because it would happen too often and would kill all the benefits of multithreading.
Instead we can create a separate data holder "ScriptingWorld". Once per frame the main thread will send a message with actual actor positions and other fast-changing information. Scripting thread will receive the message, update ScriptingWorld, run scripts, and send the changed data to the main thread. Some data that is not needed for physics and for rendering, can live in the ScriptingWorld only.
It adds an additional overhead of synchronizing the states of World and ScriptingWorld, but it likely will be insignificant in comparison with benefits of handling scripts and dehardcoded mechanics outside of the main rendering thread.
Frame rate and scripting rate
In the basic approach “scripting rate” is the same as “frame rate”. Scripts work in a separate thread, but since we synchronize it with the main thread, frames are the same. However we can consider other variants.
Let’s imagine that some mod uses a really slow Lua local script. How will it affect the game? There are several ways to handle such situations:
- Block the rendering thread until all scripts are processed. In this case the slow script drops frame rate and makes the game less playable.
- Interrupt scripts that work too long. It’s unacceptable because it can break some essential functionality.
- Don’t wait for scripts to finish, and start rendering a new frame. I.e. skip one update of the ScriptingWorld. If the script is constantly slow, we will have one scripting frame per every 2 (or even more) rendering frames. In this case “scripting rate” can be different from “frame rate” and some scripted events may happen with a minor delay, but the game will remain playable. This approach seems to be the most reasonable.
* * *
Overall I don't have a definite opinion what would be the best decision about multithreading for scripts. Any comments are welcome.