- Home /
Multithreading and messaging
Dear all,
I use multithreading rather extensively in my project for many reasons. Sometimes it's because I don't want a larger piece of work to freezy my rendering, such as saving an extensive amount of data to the harddrive, other times I do it because the nature of the work relies on careful timing that cannot be locked to a specific framerate.
Often, though, something in Unity needs to happen as a result of something that occurred in a separate thread. Like many of you, I am well aware that Unity's API isn't threadsafe and that I can't do anything that changes the renderstate from a separate thread. So, to get around this, I'm using a type of message where the separate thread changes variables which are threadsafe, and then when something visual must happen, it sets a variable which Unity's mainthread checks to see if it needs to react. This pattern is rather dirty. I've coded an example to demonstrate what it looks like:
using System;
using UnityEngine;
using System.Threading;
public class ThreadingExample : MonoBehaviour
{
Thread WorkerThread;
Boolean UnityMustReact = false;
Boolean SomeCondition = true;
void Start()
{
WorkerThread = new Thread(new ThreadStart(DoWork));
WorkerThread.Start();
}
void Update()
{
if (UnityMustReact) // This is the problem - I must check this variable all the time
{
// ... Do something that uses the work performed by the separate thread, such as using
// vectors whose values were set by the separate thread
// Done reacting, so reset variable
UnityMustReact = false;
}
}
void DoWork()
{
while (SomeCondition)
{
// Do something that needs careful timing or mustn't freeze Unity
// Set some variables that Unity uses, for example vectors to draw something
// Work is done, so I want Unity to react to it
UnityMustReact = true;
}
}
}
As you can see, this pattern is less than optimal. It involves constantly checking a boolean to see if it's time to react to changes done by the thread. This is not good, and generally, one would use a coroutine to schedule these kinds of events. But coroutines cannot be started from a separate thread.
So here's the question:
Can you come up with a cleaner way of messaging Unity to tell it to react to a separate thread's work? More specifically, I'm looking for a way to get rid of the polling. I dislike having to check a boolean every frame.
Thanks in advance and happy new year! :)
Answer by CHPedersen · Jul 09, 2012 at 01:24 PM
I had time to return to this some time ago, and decided to post the solution I went for, which is basically what Bunny suggested. :)
I developed a simple task executer into which you can "inject" code. It looks like this:
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
public delegate void Task();
public class TaskExecutorScript : MonoBehaviour {
private Queue<Task> TaskQueue = new Queue<Task>();
private object _queueLock = new object();
// Update is called once per frame
void Update () {
lock (_queueLock)
{
if (TaskQueue.Count > 0)
TaskQueue.Dequeue()();
}
}
public void ScheduleTask(Task newTask)
{
lock (_queueLock)
{
if (TaskQueue.Count < 100)
TaskQueue.Enqueue(newTask);
}
}
}
It's pretty simple, and that's why I like it. Basically, it's a queue of task objects. A Task is just an encapsulation around an anonymous function (a delegate). The ScheduleTask method adds a task to the queue, and then in Update, it executes one per frame. This is basic and can be expanded - For example, I gave it a limit of 100 tasks. If not, it's possible to overload Unity, in case a thread runs rampant and loop-adds more tasks than the main thread can execute. I also decided not to empty the entire loop in one frame, because I didn't want to run the risk of stalling the rendering and cause a chop in the graphics, in case many high-cost tasks are in the queue.
You slap this onto an empty GameObject and acquire a reference to it, then, when your thread completes whatever it's doing that needs a reaction, you can add a task like this:
GameObject taskExecutor = GameObject.Find("NameOfTheGameObjectToWhichTheTaskExecutorScriptIsAttached");
TaskExecutorScript taskExecutorScript = taskExecutor.GetComponent<TaskExecutorScript>();
taskExecutorScript.ScheduleTask(new Task(delegate
{
// Add whatever Unity API code you want here
GameObject go = Instantiate(SomePrefab);
go.transform.position = new Vector3(0, 0, 0);
// Etc
}));
This enables you to put code which is totally Unity API into event handlers executed by separate threads, because the Unity API code isn't actually executed by that thread - it gets scheduled for execution by the TaskExecutorScript.
There. I can't think of a cleaner way to do this. Case closed. :)
I was reading all of this thinking that it was a handy multithreading Scheduler-but the above code is all on the same core! As far as I can see!?
There is no guarantee what physical core it will run on. The subsystem's scheduler in hardware totally deter$$anonymous$$utes this for you, unless you specify CPU affinity in Windows. The TaskExecutor here only enables work which involves calling the Unity API to be added to the mainthread from separate threads.
Can I make ScheduleTask static? So I can access it like TaskExecutor.ScheduleTask?
No, because TaskExecutor is a $$anonymous$$onoBehaviour. It relies on the rendering loop to execute the scheduled tasks, and you can't attach static classes to GameObjects, as components are inherently instanced objects.
But you can make TaskExecutor follow the singleton pattern, so you can access it through TaskExecutor.Instance.ScheduleTask, and then encapsulate the instantiation inside a static property called Instance.
This worked a treat with an issue i encountered making bespokeOSC work in Unity. The OSCServer class uses a thread which meant the oscServer_$$anonymous$$essageReceived handler would not run on the main thread causing havoc when strangeioc signals called up on view mediators to manipulate game objects. Wrapping the handler code in a task and having it run on the update() of a dummy object solved it.
Answer by Bunny83 · Jan 02, 2012 at 02:50 PM
There are not much alternatives in Unity i guess. It depends on how many of such "events" you have at the same time and how time-critical it is. If it's a visual feedback to a quite long loading process it would be enough to check only 10 or 5 times per sec. So a coroutine which is started together with the thread-task and removed / terminated when the task is finished is the best way i guess.
If you need a lot of different events to be executed as fast as possible you might use a task-queue. Just a List of task objects which is thread-safe so every thread can add new tasks which get executed and removed by the main thread. This way you only have one check each frame. This would be quite similar to a simple custom coroutine implementation like shown here.
I like the idea of a task queue. :) I'm not sure how well it applies to my situation, but it sounds like a neat construct that I can take advantage of in other ways.
$$anonymous$$y scenario involves the reception of, and reaction to, data received through a network socket. It kind of corresponds to a GPS - I want to be able to receive data the moment it is ready, so I can update a position on a map as often as possible, so I have a different thread handle contacting the satelites and parsing the raw GPS data. This is because a separate thread can ask the socket whether data is ready more often than the main thread can render frames. Then, when a new position is ready, I need to move a character in Unity using the new data. (The actual scenario is not a GPS system, but the required solution exhibits the same behavior. ;) )
I've returned and accepted this as the right answer - I implemented it recently and liked the result. See update to initial question.
It's better you post it as answer and don't put the answer to the question in the question itself. There's also no problem when you accept your own answer.
Do you use a mutex / semaphore / lock to access the queue? I'm not sure, but as far as i know those container classes aren't thread-safe by default. It probably works fine, but there is a chance you get corrupted data if two threads access the same resource at the same time.
Alright, I'm moving the answer to a new answer below, then hitting accept on that. (Actually, I did it this way because I didn't wanna take credit - it wasn't my idea, after all).
Good point on the thread safety. It's worked perfectly up to now, but as is always the case with concurrency, there's no guarantee it won't randomly fail in the future. I've added lock statements to the ScheduleTask method and the access that takes place in Update. This should ensure thread safety.
The Queue has a Synchronized() function which returns a thread-safe wrapper for a given queue. I think that's the easiest way ;)
Answer by jef.c · Dec 30, 2011 at 11:45 PM
Could your WorkerThread fire off an event that the other one is subscribed to?
Unfortunately, no. I'm actually already using events to set the boolean, I just omitted that from the example to simplify it.
The reason why is that events are really just a list of callbacks. That's why you use "+=" when you subscribe to an event - you're attaching a function handle to a list of callbacks to be called when the event fires. Therefore, the handler of an event is called by the same thread that fires the event, not the mainthread. Thus, using the Unity API in an event handler attached to an event which is raised by a seperate thread is semantically equivalent to using the Unity API in that same thread.
Answer by junglemason · Jan 11, 2015 at 09:16 PM
You can also use the EventWaitHandle class to tell the thread to wait until a certain even happens in the main thread. Similar to events, but designed specifically for communicating between threads.
Answer by aeroson · Jul 18, 2015 at 04:53 PM
For my needs i needed to implement ISynchronizeInvoke. Can be used for what you need, and pretty much does what OP is doing now but in more .NET elegant designed way. It even supports return values from another thread.
Your answer
![](https://koobas.hobune.stream/wayback/20220613062517im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
[En & Fr] Show a message on the screen - Faire apparaître un message sur l’écran 1 Answer
Thread synchronization and .NET version issues 1 Answer
Defer graphics.blit until render thread? (Android) 1 Answer
Split screen as two processes 0 Answers
Are UnityEngine.Object types still not thread safe? 1 Answer