// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Threading;
using UnityEngine;
namespace Microsoft.MixedReality.WebRTC.Unity
{
///
/// Base class providing some utility work queue to dispatch free-threaded actions
/// to the main Unity application thread, where the handler(s) can safely access
/// Unity objects.
///
public class WorkQueue : MonoBehaviour
{
///
/// Check if the current thread is the main Unity application thread where
/// it is safe to access Unity objects.
///
///
/// Should be only called once the object is awake.
///
public bool IsMainAppThread
{
get
{
UnityEngine.Debug.Assert(_mainAppThread != null, "This method can only be called once the object is awake.");
return Thread.CurrentThread == _mainAppThread;
}
}
///
/// Ensure the current method is running on the main Unity application thread.
///
///
/// Should be only called once the object is awake.
///
[Conditional("UNITY_ASSERTIONS")]
public void EnsureIsMainAppThread()
{
UnityEngine.Debug.Assert(IsMainAppThread, "This method can only be called from the main Unity application thread.");
}
///
/// Invoke the specified action on the main Unity app thread.
///
/// The action to execute.
///
/// If this object is awake, and this method is called from the main Unity app thread,
/// will be executed synchronously. Otherwise,
/// will be called during the next call to this object's .
///
public void InvokeOnAppThread(Action action)
{
if (_mainAppThread != null && IsMainAppThread)
{
action();
}
else
{
_mainThreadWorkQueue.Enqueue(action);
}
}
protected virtual void Awake()
{
// Awake() is always called from the main Unity app thread
_mainAppThread = Thread.CurrentThread;
}
///
/// Implementation of MonoBehaviour.Update
/// to execute from the main Unity app thread any background work enqueued from free-threaded callbacks.
///
protected virtual void Update()
{
// Execute any pending work enqueued by background tasks
while (_mainThreadWorkQueue.TryDequeue(out Action workload))
{
workload();
}
}
///
/// Internal queue used to marshal work back to the main Unity app thread, which is the
/// only thread where access to Unity objects is allowed. This is used by free-threaded
/// callbacks to defer some of their work, generally a final user notification via an event.
///
private readonly ConcurrentQueue _mainThreadWorkQueue = new ConcurrentQueue();
///
/// Reference to the main Unity application thread where it is safe to access Unity objects.
///
private Thread _mainAppThread = null;
}
}