Search Unity

Thread Safe Queue<Action>

Discussion in 'Scripting' started by YogX, Jan 17, 2019.

  1. YogX

    YogX

    Joined:
    Apr 16, 2013
    Posts:
    33
    I have been using Queue<Action> in my game for a while now before realizing it is not thread safe. C# ConcurrentQueue is an option but it is not available for Unity.
    Searching Google I have found several solutions - but not really sure what is the current best way to do this.
    Can anyone share from experience?
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    you can use 'lock' to lock the queue when you need to access it. You just have to manage this correctly to make sure you don't accidentaly deadlock on your queue (a situation where 2 threads rely on the resource but when one locks on it, some logic elsewhere, usually in the other thread, keeps it from unlocking).

    I know ConcurrentQueue was introduced in .net 4.x. I haven't really played a lot with threading in 4.x in Unity (only outside of Unity), but I would assume if you targeted 4.x you'd get access to it. Someone else can correct me if I'm wrong though. As I said, within Unity, I haven't necessarily dug around in that library (noting I use .net outside of Unity for enterprise stuff mostly).
     
  3. YogX

    YogX

    Joined:
    Apr 16, 2013
    Posts:
    33
    Not sure I want to upgrade yet. I'm also not sure what kind of a performance hit moving to a normal Queue but with locks around everything will cause.
     
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    the performance hit to using a lock will be when 2 threads access at the same time.

    The thread that "loses" will block until it's unlocked. If you only lock for the Dequeue/Enqueue, it shouldn't take very long.

    In the same respect a ConcurrentQueue will also have a similarish performance issue, becuase it too has to resolve internally for concurrent access. As you can see from this mono implementation it uses a SpinWait and volatile:
    https://github.com/mono/mono/blob/m...ollections/Concurrent/ConcurrentQueue.cs#L577
     
    phindle likes this.
  5. phindle

    phindle

    Joined:
    Nov 7, 2013
    Posts:
    1
    I'm using ConcurrentQueue<T> in a Unity 2019.1.2 project. It just dropped in easily for Queue<T> with a small change. (queue.Dequeue() had to be replaced with queue.TryDequeue( out T ).

    My use case is where network payloads arrive via an Event, and the callback is not on the main thread. So if I try and move transforms here in this context, Unity throws an exception like this:
    Code (CSharp):
    1. UnityEngine.UnityException: get_transform can only be called from the main thread.
    So I just push the payload into a ConcurrentQueue, and then handle each of the queued network payloads in the Update() method of the behaviour.
     
    MadMojo and Joe-Censored like this.
  6. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I use ConcurrentQueue in Unity as part of my network code when moving network messages between the main thread and the network threads. Works fine. Not available in the legacy .net 3.5 back end though.

    I also use it to write Debug.Log messages from other threads, where I just write the strings to a ConcurrentQueue and on the main thread actually call Debug.Log. I've found it pretty handy.

    (project currently on 2018.2.9 still by the way)
     
    MadMojo likes this.