Skip to content

Instantly share code, notes, and snippets.

@glebov21
Created February 2, 2018 08:42
Show Gist options
  • Save glebov21/9898bfb0dbe6183d67a1c4945a13f215 to your computer and use it in GitHub Desktop.
Save glebov21/9898bfb0dbe6183d67a1c4945a13f215 to your computer and use it in GitHub Desktop.
unity3d MainThread
/* Attach this to any object in your scene, to make it work */
using System;
using System.Collections;
using UnityEngine;
using System.Threading;
public class MainThread : MonoBehaviour
{
private static InvokePump mPump;
void Start()
{
mPump = new InvokePump(); //it was created in the main thread, so the owner thread is main thread
StartCoroutine(Executer());
}
public static void Call(Action<object> func, object obj)
{
mPump.BeginInvoke(() => { func(obj); });
}
public static void Call(Action func)
{
mPump.BeginInvoke(func);
}
public static void Call<TObj, TArgs>(EventHandler<TArgs> func, TObj obj, TArgs args) where TArgs : EventArgs
{
mPump.BeginInvoke(() => { func(obj, args); });
}
public static bool isInitialized()
{
return (mPump != null);
}
IEnumerator Executer()
{
while (true)
{
mPump.Update();
yield return null;
}
}
}
/// <summary>
/// Queue actions up to be called during some other threads update pump.
/// </summary>
public class InvokePump : WaitHandle
{
#region Fields
private int _threadId;
private Action _invoking;
private object _invokeLock = new object();
private EventWaitHandle _waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
private EventWaitHandle _waitHandleAlt = new EventWaitHandle(false, EventResetMode.AutoReset);
#endregion
#region CONSTRUCTOR
public InvokePump()
: this(null)
{
}
public InvokePump(Thread ownerThread)
{
_threadId = (ownerThread != null) ? ownerThread.ManagedThreadId : System.Threading.Thread.CurrentThread.ManagedThreadId;
}
#endregion
#region Properties
/// <summary>
/// Returns true if on a thread other than the one that owns this pump.
/// </summary>
public bool InvokeRequired
{
get { return _threadId != 0 && Thread.CurrentThread.ManagedThreadId != _threadId; }
}
#endregion
#region Methods
/// <summary>
/// Queues an action to be invoked next time Update is called. This method will block until that occurs.
/// </summary>
/// <param name="action"></param>
public void Invoke(Action action)
{
if (_threadId == 0) throw new System.InvalidOperationException("InvokePump has been closed.");
if (Thread.CurrentThread.ManagedThreadId == _threadId) throw new System.InvalidOperationException("Never call WaitOne on an InvokePump from the thread that owns it, this will freeze that thread indefinitely.");
if (action == null) throw new System.ArgumentNullException("action");
lock (_invokeLock)
{
_invoking += action;
}
_waitHandle.WaitOne(); //block until it's called
}
/// <summary>
/// Queues an action to be invoked next time Update is called. This method does not block.
/// </summary>
/// <param name="action"></param>
public void BeginInvoke(Action action)
{
if (_threadId == 0) throw new System.InvalidOperationException("InvokePump has been closed.");
if (action == null) throw new System.ArgumentNullException("action");
lock (_invokeLock)
{
_invoking += action;
}
}
/// <summary>
/// Can only be called by the thread that owns this InvokePump, this will run all queued actions.
/// </summary>
public void Update()
{
if (_threadId == 0) return; //we're destroyed
if (this.InvokeRequired) throw new System.InvalidOperationException("InvokePump.Update can only be updated on the thread that was designated its owner.");
if (_invoking != null)
{
Action act;
EventWaitHandle handle;
lock (_invokeLock)
{
act = _invoking;
handle = _waitHandle;
_invoking = null;
_waitHandle = _waitHandleAlt;
_waitHandleAlt = handle;
}
//call delegate
act();
//release waits
handle.Set();
}
}
#endregion
#region Overrides
public override void Close()
{
base.Close();
if (_threadId == 0) return; //already was destroyed
_waitHandle.Close();
_waitHandleAlt.Close();
_threadId = 0;
}
protected override void Dispose(bool explicitDisposing)
{
base.Dispose(explicitDisposing);
if (_threadId == 0) return; //already was destroyed
(_waitHandle as IDisposable).Dispose();
(_waitHandleAlt as IDisposable).Dispose();
_threadId = 0;
}
public override bool WaitOne()
{
if (_threadId == 0) throw new System.InvalidOperationException("InvokePump has been closed.");
if (Thread.CurrentThread.ManagedThreadId == _threadId) throw new System.InvalidOperationException("Never call WaitOne on an InvokePump from the thread that owns it, this will freeze that thread indefinitely.");
return _waitHandle.WaitOne();
}
public override bool WaitOne(int millisecondsTimeout)
{
if (_threadId == 0) throw new System.InvalidOperationException("InvokePump has been closed.");
if (Thread.CurrentThread.ManagedThreadId == _threadId) throw new System.InvalidOperationException("Never call WaitOne on an InvokePump from the thread that owns it, this will freeze that thread indefinitely.");
return _waitHandle.WaitOne(millisecondsTimeout);
}
public override bool WaitOne(int millisecondsTimeout, bool exitContext)
{
if (_threadId == 0) throw new System.InvalidOperationException("InvokePump has been closed.");
if (Thread.CurrentThread.ManagedThreadId == _threadId) throw new System.InvalidOperationException("Never call WaitOne on an InvokePump from the thread that owns it, this will freeze that thread indefinitely.");
return _waitHandle.WaitOne(millisecondsTimeout, exitContext);
}
public override bool WaitOne(TimeSpan timeout)
{
if (_threadId == 0) throw new System.InvalidOperationException("InvokePump has been closed.");
if (Thread.CurrentThread.ManagedThreadId == _threadId) throw new System.InvalidOperationException("Never call WaitOne on an InvokePump from the thread that owns it, this will freeze that thread indefinitely.");
return _waitHandle.WaitOne(timeout);
}
public override bool WaitOne(TimeSpan timeout, bool exitContext)
{
if (_threadId == 0) throw new System.InvalidOperationException("InvokePump has been closed.");
if (Thread.CurrentThread.ManagedThreadId == _threadId) throw new System.InvalidOperationException("Never call WaitOne on an InvokePump from the thread that owns it, this will freeze that thread indefinitely.");
return _waitHandle.WaitOne(timeout, exitContext);
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment