The solution works by keeping track of a list of tasks(a queue) that need to be executed in the main thread, and then run through that queue in the Update()
via HandleTasks()
; executing and removing each one from the queue. You can add to the task queue by calling QueueOnMainThread()
and passing an anonymous function.
I got some inspiration from this answer by Pragmateek
You can have a separate script to manage main thread tasks or just incorporate it into your already existing script where you need to run something in the main thread.
Here is the full source, fixed solution to my original snippet in the question.
Below is just the necessary bits to get the queuing up and running:
// We use this to keep tasks needed to run in the main thread
private static readonly Queue<Action> tasks = new Queue<Action>();
void Update () {
this.HandleTasks();
}
void HandleTasks() {
while (tasks.Count > 0)
{
Action task = null;
lock (tasks)
{
if (tasks.Count > 0)
{
task = tasks.Dequeue();
}
}
task();
}
}
public void QueueOnMainThread(Action task)
{
lock (tasks)
{
tasks.Enqueue(task);
}
}
To Queue something up on the main thread just pass it a lambda expression:
this.QueueOnMainThread(() => {
// We are now in the main thread...
Debug.Log("maxConnections: " + Network.maxConnections);
});
If you are using WinForms, this article: Avoiding InvokeRequired has some great coding patterns.