reckfellENGINE

Thread safety: the Entity tree, data and ownership

What stays on the main thread, what a worker can own, and why a mutex or CallDeferred is not a universal fix.

On this page

Practical boundary

For an ordinary C# Task or worker, keep the active Entity tree and UI on the main thread. Pass an independent input snapshot, return an independent result and apply it only while still relevant. The complete example does this through _Process.

Object/operationRule for this example and an ordinary C# worker
Active-tree Entity, AddChild, removal, Label/Text and game stateMain thread; do not capture them in a computation lambda
Numbers, strings, an exclusively owned arrayCan be passed to a worker; do not modify the same data concurrently
Shared List/Dictionary or collection resizingRequires a consistent locking protocol or suitable concurrent collection; an ordinary collection does not supply one
Resource, material, texture, PackedEntityA reference may identify a shared object; copying the reference does not copy its data
Native server API, loading, rendering and physicsCheck the specific method, backend and configuration; there is no blanket permission that every singleton is thread-safe

Main thread in this table does not imply that the engine lacks other processing modes. ProcessThreadGroup and subsystem threads have their own rules. Task.Run does not join an authorized Entity processing group simply because it uses a pool.

Why a lock is insufficient

A lock protects your data only when every participant takes the same lock. It does not change the engine's main-thread requirement for AddChild or make a renderer acquire your mutex. The fixture performs an actual active-tree AddChild from a .NET worker: the engine rejects it and no child is added.

No diagnostic in another build does not establish safety: checks may depend on configuration. Do not disable thread checks to silence a message. Fix ownership and where the operation executes.

Do not hold a lock while waiting for another job or the main thread. If the main thread waits for a worker and the worker waits for a main-thread action, they deadlock. Cancellation cannot break that cycle if code does not check it or waits indefinitely.

Transferring a result

CallDeferred queues later processing; it is neither a completed operation nor a promise of a particular next frame. It does not copy arbitrary mutable C# objects or extend the lifetime of every reference captured by a lambda. Deferred application still needs a valid receiver, result ownership and a stale-request rule.

BackgroundJob reads the result after Task completion in _Process. Tree exit cancels the job, and its continuation never accesses the Entity. PoolPrimeBatch copies its input and publishes output only after joining. These are specific ownership rules, not a one-time object-validity check before another thread uses it.

Parallel writes to distinct preallocated array indices can form a valid protocol when indices do not overlap, the array does not resize, output is unread until completion and faults are handled. The example's group uses that protocol. It does not authorize simultaneous edits to shared Resource collections or another Entity's properties.

Resources and expensive preparation

Use the loader's intended loading API, then instantiate and attach Entity objects under its lifecycle rules. Do not move Instantiate, shared-material mutation and AddChild into Task.Run by analogy with pure number computation. Even an object outside the tree can reference shared resources and invoke server operations.

Move only the demonstrably independent portion. Native thread safety of one method does not remove application data races, and a managed concurrent collection does not make the native objects it contains safe. Exports, other backends and special processing groups require separate verification.

Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.