-
-
Save yoshikischmitz/34a7cd476ce53b5e24fc1561520340f0 to your computer and use it in GitHub Desktop.
Implementation of ISynchronizeInvoke for Unity3D game engine. Can be used to invoke anything on main Unity thread. ISynchronizeInvoke is used extensively in .NET forms, it's is elegant and quite useful in Unity as well. I implemented it so i can use it with System.IO.FileSystemWatcher.SynchronizingObject.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Implementation of ISynchronizeInvoke for Unity3D game engine. | |
Can be used to invoke anything on main Unity thread. | |
ISynchronizeInvoke is used extensively in .NET forms, it's is elegant and quite useful in Unity as well. | |
I implemented it so i can use it with System.IO.FileSystemWatcher.SynchronizingObject. | |
help from: http://www.codeproject.com/Articles/12082/A-DelegateQueue-Class | |
example usage: https://gist.github.com/aeroson/90bf21be3fdc4829e631 | |
license: WTFPL (http://www.wtfpl.net/) | |
contact: aeroson (theaeroson @gmail.com) | |
*/ | |
using System.Collections; | |
using System.Threading; | |
using System.ComponentModel; | |
using System.Collections.Generic; | |
using System.Reflection; | |
using System; | |
public class UnitySynchronizeInvoke : ISynchronizeInvoke | |
{ | |
Queue<UnityAsyncResult> fifoToExecute = new Queue<UnityAsyncResult>(); | |
Thread mainThread; | |
public bool InvokeRequired { get { return mainThread.ManagedThreadId != Thread.CurrentThread.ManagedThreadId; } } | |
public UnitySynchronizeInvoke() | |
{ | |
mainThread = Thread.CurrentThread; | |
} | |
public IAsyncResult BeginInvoke(Delegate method, object[] args) | |
{ | |
var asyncResult = new UnityAsyncResult() | |
{ | |
method = method, | |
args = args, | |
IsCompleted = false, | |
AsyncWaitHandle = new ManualResetEvent(false), | |
}; | |
lock (fifoToExecute) | |
{ | |
fifoToExecute.Enqueue(asyncResult); | |
} | |
return asyncResult; | |
} | |
public object EndInvoke(IAsyncResult result) | |
{ | |
if (!result.IsCompleted) | |
{ | |
result.AsyncWaitHandle.WaitOne(); | |
} | |
return result.AsyncState; | |
} | |
public object Invoke(Delegate method, object[] args) { | |
if (InvokeRequired) | |
{ | |
var asyncResult = BeginInvoke(method, args); | |
return EndInvoke(asyncResult); | |
} | |
else | |
{ | |
return method.DynamicInvoke(args); | |
} | |
} | |
public void ProcessQueue() | |
{ | |
if (Thread.CurrentThread != mainThread) | |
{ | |
throw new Exception("Must be called from the same thread it was created on"); | |
} | |
bool loop = true; | |
UnityAsyncResult data = null; | |
while (loop) | |
{ | |
lock (fifoToExecute) | |
{ | |
loop = fifoToExecute.Count > 0; | |
if (!loop) break; | |
data = fifoToExecute.Dequeue(); | |
} | |
data.AsyncState = Invoke(data.method, data.args); | |
data.IsCompleted = true; | |
} | |
} | |
class UnityAsyncResult : IAsyncResult | |
{ | |
public Delegate method; | |
public object[] args; | |
public bool IsCompleted { get; set; } | |
public WaitHandle AsyncWaitHandle { get; internal set; } | |
public object AsyncState { get; set; } | |
public bool CompletedSynchronously { get { return IsCompleted; } } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Threading; | |
public class UnitySynchronizeInvokeExample : MonoBehaviour | |
{ | |
UnitySynchronizeInvoke synchronizeInvoke; | |
void Start() | |
{ | |
synchronizeInvoke = new UnitySynchronizeInvoke(); | |
(new Thread(ThreadMain)).Start(); | |
} | |
void ThreadMain() | |
{ | |
while (true) | |
{ | |
var retObj = synchronizeInvoke.Invoke((System.Func<string>)(() => | |
{ | |
this.transform.localScale = Vector3.one * Random.Range(1.0f, 10.0f); | |
return this.gameObject.name; | |
}), null); | |
Debug.Log("Waited for the end of synchronizeInvoke and it synchronously returned me: " + (retObj as string)); | |
Thread.Sleep(1 * 1000); | |
} | |
} | |
void Update() | |
{ | |
synchronizeInvoke.ProcessQueue(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment