Skip to content

Instantly share code, notes, and snippets.

@starikcetin
Last active July 27, 2022 16:45
Show Gist options
  • Save starikcetin/7f7d922d92672570abd71ef3adf60668 to your computer and use it in GitHub Desktop.
Save starikcetin/7f7d922d92672570abd71ef3adf60668 to your computer and use it in GitHub Desktop.
Main thread dispatcher for Unity.
using System;
using System.Threading;
// TODO: Make sure Singleton implementation is also thread-safe.
/// <summary>
/// Provides means of executing code on the main Unity thread while in other threads.
/// </summary>
public class MainThreadDispatcher
{
private readonly SynchronizationContext _syncContext = SynchronizationContext.Current;
/// <summary>
/// Dispatches an action to the Unity main thread, and waits for either an answer or action completion.
/// </summary>
/// <remarks>
/// This code, when run in a background thread:
/// <code>
/// Debug.Log("Before");
/// MainThreadDispatcher.Instance.DispatchAndWait(() =&gt; Debug.Log("Inside"));
/// Debug.Log("After");
/// </code>
/// Produces the following console output:
/// <code>
/// Before
/// Inside
/// After
/// </code>
/// Notice 'After' appearing after 'Inside'.
/// </remarks>
/// <seealso cref="DispatchFireAndForget"/>
public void DispatchAndWait(Action action)
{
_syncContext.Send(_ => action?.Invoke(), null);
}
/// <summary>
/// Dispatches an action to the Unity main thread but doesn't wait for an answer or action completion.
/// </summary>
/// <remarks>
/// This code, when run in a background thread:
/// <code>
/// Debug.Log("Before");
/// MainThreadDispatcher.Instance.DispatchFireAndForget(() =&gt; Debug.Log("Inside"));
/// Debug.Log("After");
/// </code>
/// Produces the following console output:
/// <code>
/// Before
/// After
/// Inside
/// </code>
/// Notice 'After' appearing before 'Inside'.
/// </remarks>
/// <seealso cref="DispatchAndWait"/>
public void DispatchFireAndForget(Action action)
{
_syncContext.Post(_ => action?.Invoke(), null);
}
//
// Alternative implementation below with a ConcurrentQueue:
//
// private readonly ConcurrentQueue<Action> _queue = new ConcurrentQueue<Action>();
//
// public void Dispatch(Action action)
// {
// _queue.Enqueue(action);
// }
//
// private void Update()
// {
// if (_queue.IsEmpty)
// {
// return;
// }
//
// while (_queue.TryDequeue(out var action))
// {
// action?.Invoke();
// }
// }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment