Scene and its various SceneSystem implement muti-threading using a lock-free model with a single synchronization point per frame to allow maximum scalability even with a large number of HW thread available.
While not mandatory, a minimal understanding of the model concepts is recommended as it has implications that might seem unclear otherwise.
The scene update is split in two phases: Update and Commit. The Update phase is read-only while the Commit phase is read-write. Every write to the scene or any of its Component or Node during the Update phase is queued for execution in the Commit phase.
The following sequence performs a complete update of the scene and its systems.
scene.Update() # start the Update phase while not scene.WaitUpdate(): # wait for the Update phase to end pass # note that the caller thread (interpreter) is not blocked scene.Commit() # start the Commit phase scene.WaitCommit() # wait for the Commit phase to end
Note: The complete scene should not be accessed in any ways during the commit phase. Since this issue is entirely avoided with a blocking WaitCommit it is the default.
The update phase is by far the slowest of the two phases, often 10x to 100x slower than the commit phase. The commit phase is usually very fast even with a large number of writes to perform.
In some cases, it could be necessary to execute a non-blocking WaitCommit or WaitUpdate. You have to make sure the wait function returns true before proceeding.
Example with WaitCommit():
scene.Commit() while not scene.WaitCommit(False): HeavyDutyComputations() scene.Update()
In such a loop, HARFANG3D must be considered locked.
Failing to wait for WaitUpdate/WaitCommit to complete execution will lead to undefined behavior and will most likely result in a low-level crash.
In the following example
my_node_pos will contain the previous node position until the next commit completes.
-- from a Lua script component my_node.transform:SetPosition(hg.Vector3(0, 10, 0)) my_node_pos = my_node.transform:GetPosition() -- my_node_pos is hg.Vector3(0, 0, 0)!
In the next example
node will not appear in the scene until the next commit completes.
-- from a Lua script component old_node_count = #scene:GetNodes() scene.AddNode(hg.Node()) new_node_count = #scene:GetNodes() -- new_node_count equals old_node_count!
Basically any operation that requires writing to the scene state will have its effects observable only on the next Update.
While these examples might seem difficult to deal with at first sight they really are not in practice. The engine hides all the complexity from you and provides the tools needed to efficiently work asynchronously.
Last but not least, this model guarantees value coherency over a single update. This means that two reads from the same property will always return the same result over a single update.