A thread safe way of updating the main thread from another thread in Unity
As you develop your game or project, you may require updating the main thread from within another thread. If you’re stuck and need a solution, here’s a quick way to get things moving.
The code defines a class named MainThreadDispatcher
. This class is designed to enable the execution of actions on the main Unity thread from other threads in a thread-safe manner. It accomplishes this by using a ConcurrentQueue
to store and process actions, and ConcurrentQueue handles all synchronization internally.
The Update
method is automatically called once per frame by Unity, and it dequeues and executes actions from the concurrentActionQueue
while ensuring that the operation is thread-safe. Additionally, a static method EnqueueAction
is provided to allow other parts of the code to enqueue actions for execution on the main thread.
This mechanism is useful for handling tasks that require interaction with Unity’s main thread from background or worker threads, such as updating UI elements, handling game events, or modifying Unity objects in a thread-safe way.
To use this, create a GameObject in your scene and attach a script with the following:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Collections.Concurrent;
using System;
public class MainThreadDispatcher : MonoBehaviour
{
private static ConcurrentQueue<Action> concurrentActionQueue = new ConcurrentQueue<Action>();
// Update is called once per frame
void Update()
{
while (concurrentActionQueue.TryDequeue(out var actionItem))
{
actionItem();
}
}
public static void EnqueueAction(Action action)
{
concurrentActionQueue.Enqueue(action);
}
}
ThreadWorker example to test the MainThreadDispatcher:
MainThreadDispatcher
.EnqueueAction
method queues an actions for execution on the Unity main thread. A lambda expression is used to encapsulate a set of actions. By enqueuing this lambda expression, it ensures that these actions are performed on the main thread, thereby safely allowing changes to Unity objects and user interface elements without risking threading issues.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
public class ThreadedWork : MonoBehaviour
{
private bool isUpdating = false;
void Start()
{
// Start a background thread to perform work
Thread backgroundThread = new Thread(PerformBackgroundWork);
backgroundThread.Start();
}
private void PerformBackgroundWork()
{
while(true)
{
// Simulate some work on a different thread
Thread.Sleep(5000);
// To update the main thread, enqueue an action
MainThreadDispatcher.EnqueueAction(() =>
{
isUpdating = true;
// Perform any updates or modifications to Unity objects here
isUpdating = false;
});
}
}
}