2.9.16
Coherent GT Unity3D Guide
A modern user interface library for games
Asynchronous mode

Coherent GT has support for multithreading which can greatly enhance your game's performance at an added complexity cost.

When using the async mode, most calls to Coherent GT are deferred and executed on another thread. We guarantee that your callbacks and event listeners will still be run on the main thread (the thread that they are registered on, that is).

Furthermore, Coherent GT will never deadlock but race conditions are unavoidable and as such the user must protect against them by himself.

Using the debugger

Enabling the async mode is as simple as checking the Run Asynchronously option in the CoherentGTSystem component.

Note that some methods are always synchronous and will block your main thread no matter what the current mode is. These methods are:

  • Coherent.UIGT.View.Destroy and destroying the view component.
  • any method that can change the currently loaded URL of a view (Coherent.UIGT.View.GoForward, Coherent.UIGT.View.LoadURL, etc.)
  • IME methods (Coherent.UIGT.View.IMESetComposition, etc.) Additionaly the initialization and uninitialization of the UI System are also synchronous.

Debugging JavaScript

Asynchronous mode implies that the JavaScript execution is also deferred on the UI thread. This may require some changes if your existing code depends on the fact that up to now, callbacks were executed in the same stack.

Consider the following communication:

C#:

void Bar()
{
    // Code
}

// During initialization
view.BindCall("Bar", (System.Action)this.Bar);

// During your main loop
view.TriggerEvent("foo");

JS:

engine.on("foo", function fooHandler() {
    // Code
    engine.trigger("bar");
});

Calling view.TriggerEvent("foo") in the synchronous mode will execute the methods in the following simplified callstack:

Callstack
Bar
JavaScript fooHandler
View TriggerEvent
GameLoop

In the async mode you get no such guarantee. fooHandler will be executed whenever the UI thread gets to it and Bar will be executed during the first View.Layout or View.ExecuteJSTimers after fooHandler has completed.

Remove implicit dependencies on synchronous mode

Let's look at a more concrete example

C#:

void StartGame()
{
    // Initialize the game
}

// During initialization
view.BindCall("StartGame", (System.Action)this.StartGame);

JS:

startButton.addEventListener("click", function () {
    engine.trigger("StartGame");
    doSomethingAssumingTheGameHasStarted();
});

If you are running in a synchronous mode, this code will work fine. When the button is clicked, the engine will call StartGame immediately, which will in turn initialize the game. Thus, by the time engine.call("StartGame") returns you can assume that everything is ready.

This assumption does not hold in asynchronous mode as the execution of StartGame will be delayed. To cope with this, use another event to notify the JS that everything is ready:

C#:

void StartGame()
{
    // Initialize the game
    view.TriggerEvent(GameStarted);
}

// During initialization
view.BindCall("StartGame", (System.Action)this.StartGame);

JS:

startButton.addEventListener("click", function () {
    engine.call("StartGame");
});

engine.on("GameStarted", function () {
    doSomethingAssumingTheGameHasStarted();
});

Usage Summary

  • If your code depends on the assumption that Coherent GT works synchronously, small changes to it will be required.
  • Working with the asynchronous mode resembles the model that most web applications use. You might think about the game as the server and your UI as its client
  • Multithreading requires thorough understanding of the threading model in order to minimize the errors and maximize the profits.

Debugger in detail

Knowing what Coherent GT does under the hood might be useful if you run into any problems.

If you are to call Coherent.UIGT.View.Layout for example, instead of running the layout immediately, Coherent GT will now post a job task to another thread (the UI thread) via a queue. The UI thread waits for any tasks to be posted and executes them in order. Note that Coherent will wait for the previous call to layout for this view to complete before issuing the next command in the interest of preventing overtasking the UI thread.

The UI thread can communicate to the main thread via another task queue. For example, when the time for execution of your event handlers (registered via Coherent.UIGT.View.RegisterForEvent or through your custom view listener) comes, the UI thread will ask the main thread to run the callback. This guarantees that your code runs only on the main thread. Most of these events will be triggered during the call to Coherent.UIGT.View.Layout.

Note that there are no changes to Coherent.UIGT.ViewRenderer and you can still paint the view on your rendering thread without complications.