Search Unity

  1. We would like to hear your feedback about Unity and our products. Click here for more information.
    Dismiss Notice

Dispatching functions to the main thread from other threads in Unity

Discussion in 'Scripting' started by pdwitte, Apr 2, 2016.

  1. pdwitte

    pdwitte

    Joined:
    Feb 3, 2016
    Posts:
    17
    Hey all, I need your feedback on something!

    So I ran into a problem this week where Unity did not allow for a simple way of executing UI functions from different threads. It blocks the modification of scene-related objects from other threads. This is quite annoying, especially if you're working with certain multithreaded networking libraries that dispatch event handlers to different threads.

    I made a quick fix for it that is easy to use and noob-friendly. It uses coroutines that are queued in a thread-safe way and executed on the main thread through a game object that is added to the scene.

    Can you guys let me know if this is useful at all, or if I should be doing it another way?

    You can use it like this:
    Code (CSharp):
    1. public IEnumerator ThisWillBeExecutedOnTheMainThread() {
    2.     Debug.Log ("This is executed from the main thread");
    3.     yield return null;
    4. }
    5. public void ExampleMainThreadCall() {
    6.     UnityMainThreadDispatcher.Instance().Enqueue(ThisWillBeExecutedOnTheMainThread());
    7. }
    Simply head over to https://github.com/PimDeWitte/UnityMainThreadDispatcher and start using it if you'd like.
     
    nizmym, codestage and mgear like this.
  2. Jamster

    Jamster

    Joined:
    Apr 28, 2012
    Posts:
    995
    I recently had to write similar for the new version of my DarkRift Networking asset, it's interesting to see your version :)

    Looks good, mostly thread safe but you should have a lock in your update routine as well because you could end up enqueuing and dequeuing at the same time which could cause you problems irregulally. I would also suggest using the built in thread safe collections in System.Collections.Concurrent if you can, it just ensures it's 100% safe and implemented in the best way possible :)

    Good work!

    Jamie
     
  3. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    25,221
    use correct forum.
     
  4. zoran404

    zoran404

    Joined:
    Jan 11, 2015
    Posts:
    519
    He does it to promote the repository, it would probably be lost in the scripting sub-forum with all the questions.

    Also I don't like the implementation, you can't use lambda-s or normal functions, but only ienumerators.
     
    Last edited: Apr 2, 2016
    Fattie likes this.
  5. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    25,221
    It is a scripting question. If he wants to promote it, it must be done in the correct forum, ie showcase or wip. We had reports for this thread and acted accordingly, personal feelings don't enter into it.
     
  6. pdwitte

    pdwitte

    Joined:
    Feb 3, 2016
    Posts:
    17
    Truthfully it was not to promote the repository. I have about 3 months in Unity and recently started after about 7 years of Java development. I'm committing this code and wanted to make sure it was the right way to do it before telling other people it is.
     
    Fattie likes this.
  7. pdwitte

    pdwitte

    Joined:
    Feb 3, 2016
    Posts:
    17
    Apologies for not using the correct forum! Pretty new as you can see, will be more careful next time.
     
  8. pdwitte

    pdwitte

    Joined:
    Feb 3, 2016
    Posts:
    17
    Thanks dude. Appreciate it, and good point on dequeuing. You're totally right. That could happen, made the change: https://github.com/PimDeWitte/Unity...mmit/17d5d0c3214e1adad0ac500adda89d4bc8b00b35
     
    Fattie likes this.
  9. lp35

    lp35

    Joined:
    Apr 25, 2017
    Posts:
    1
    Hi,

    Your script is very simple and straigthforward to understand. One remark, I really miss an EnqueueAndBlock function...
     
  10. zoran404

    zoran404

    Joined:
    Jan 11, 2015
    Posts:
    519
    You could use callbacks to accomplish whatever you need.
     
  11. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,197
    Hello. Found this thread while working on similar code called `CoroutineHost`. I took the hint of using lock to my own code from this thread.

    It is almost the same, but it does not require placing a game object beforehand. In exchange, if you want to do it cross thread you have to call `CoroutineHost.PrepareCrossThread()` to instantiate it manually.

    Also it supports modern C# like `Task` if you are using .NET 4.6 of Unity 2017. You can `await` for things in the main thread from your child thread with this.

    https://github.com/5argon/E7Unity/tree/master/CoroutineHost
     
    Jamster likes this.
  12. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    411
    @5argon , your script CoroutineHost is fine, but,

    I really suggest it's a bad idea to automatically mount a MonoBehavior to an automatic game object

    It's just not good engineering. Just present it as a plain MonoBehavior.

    It is totally impossible that anyone using Unity, dealing with threads, would not know how to make the class available on a persistent monobehavior

    Every single Unity project (other than a trivial demo) has it's own approach to handling persistent objects, and, it's pointless adding another approach!

    I suggest it would be much better just as a plain

    (note that your system to make sure it is "singleton like" .. doesn't work. I can easily break it so there are two of them. It is really just a pointless idea trying to "auto-game-object" in Unity. :O )

    Note - there's a thing on the asset store where they take the approach of simply making it a static,

    https://assetstore.unity.com/packages/tools/ezthread-coroutine-replacement-easy-threads-62507

    I have not checked it out yet
     
    hippocoder likes this.
  13. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,197
    Wow I almost forgot this. Nowadays I am using UniRx.Async instead. What it did is utilizing the experimental PlayerLoop API and add some custom callback points into it. This way it doesn't even have to rely on any game object and also I can make it work with C# async/await. await will turns into frame-waiting await just like how yield enumerate waiting works, but with cleaner code and return values.

    https://github.com/neuecc/UniRx#unirxasync
     
    hippocoder likes this.
  14. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    411
    Thanks for that fascinating tip, @5argon !! Cheers