You usually do not have to care about multi-threading beyond performing the worker pool initialization (see CreateWorkers). The API is designed in a way to prevent common and often difficult to diagnose multi-threading errors.

There are however a few interfaces that cannot be used safely when using multiple threads.

The Renderer, RenderSystem and Mixer interfaces cannot be used directly when running on multiple threads, the equivalent RendererAsync, RenderSystemAsync and MixerAsync interfaces must be used instead.

The Scene related objects multi-threading model is described in Scene multi-threading model.

Asynchronous wrapper classes

Some classes, such as RendererAsync, are asynchronous wrapper for other classes (Renderer in this case). They expose almost the same API as the class they wrap with the difference that calls to their member functions will be queued instead of being executed immediately.

The queued calls will be picked up and executed in the original call order by a worker thread.

RendererAsync is required to safely call graphic APIs from any thread. For example, when writing program in Python this is the only way to call into the graphic API as the Python interpreter is running in a different thread than the graphic API.

Of course, using RendererAsync would be very inefficient when executing from the graphic thread. This is the case when executing code inside a rendering callback. If you know that you are executing from the graphic thread it is much more efficient to use Renderer directly.

Getting the return value from an asynchronous call

You might wonder how to get the return value from a function if it is only going to get executed in the future. To solve this problem asynchronous wrappers return future value objects (see FutureBool, FutureInt for example).

These future objects can be queried to determine if a queued function has finished executind and if its return value has been made available. The get method will block the caller thread until the return value is available.

Since this might block your program for an unpredictable amount of time a better design is to call valid() on the future object then take another action (eg. play a wait animation) if the value is not available yet.