Search Unity

Problem interacting with Unity using threads

Discussion in 'Multiplayer' started by maozao, Jan 29, 2019.

  1. maozao

    maozao

    Joined:
    Jan 20, 2016
    Posts:
    12
    Hello.

    I'm having problems to interact with Unity (objects, Scenes, etc) inside a thread, since looks like Unity doesn't allow modifications on its thread from a different one.

    I kinda found a way to work with that, but I really don't like the way I'm using, so I want to know if someone of you guys have some better idea to deal with it.

    Current situation, I'm starting a new Thread to read/write the TCP packets from/to the server, since I can not use anything from Unity inside of it, I'm adding the packets I'm receiving into a Queue list and reading the list from a Cooroutine.

    This is my current code:

    Code (CSharp):
    1. private Queue<object> packetsToProcess = new Queue<object>();
    2. void Awake() {
    3.     StartCoroutine("ProcessPacketsCoroutine");
    4.  
    5.     Thread t = new Thread(new ThreadStart(AuthenticateUser));
    6.     t.IsBackground = true;
    7.     t.Start();
    8. }
    9.  
    10. private void AuthenticateUser() {
    11.     // Code to open connection and get the stream data, etc
    12.     if (packetType == AuthFailed)
    13.                     {
    14.                         AuthFailed p = new AuthFailed();
    15.                         packetsToProcess.Enqueue(p);
    16.                         break;
    17.                     }
    18.     else if (packetType == AuthSuccess) {
    19.         // SceneManager.LoadScene(1, LoadSceneMode.Single); // Can not do this here, Unity crash
    20.         packetsToProcess.Enqueue(new AuthSuccess());
    21.     }
    22. }
    23.  
    24. private IEnumerator ProcessPacketsCoroutine()
    25.     {
    26.         while(true)
    27.         {
    28.            
    29.             if(packetsToProcess.Count == 0)
    30.                 yield return new WaitForSeconds(0.5f);
    31.  
    32.             var packet = packetsToProcess.Dequeue();
    33.             if(packet is AuthFailed)
    34.             {
    35.                 ErrorText = "Wrong Auth!";
    36.             }
    37.             else if (packet is AuthSuccess) {
    38.                 SceneManager.LoadScene(1, LoadSceneMode.Single); // Here it works, since it's a CoRoutine
    39.             }
    40. }
    Of course it's a totally simplified code, the point is to show the problem with the SceneManager.LoadScene (in this case) and the workaround I found to proccess the packets.

    Any ideas what could be done?
     
  2. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I don't believe a Queue is thread safe. I use ConcurrentQueue for this. Requires .net 4.x.
     
  3. maozao

    maozao

    Joined:
    Jan 20, 2016
    Posts:
    12
    Well, I had no problems using Queue, but I'm gonna take a look in the ConcurrentQueue, but that's not really the problem described, the Queue was just a workaround since I can not call for example, SceneManager.LoadScene(), inside the new Thread.
     
  4. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I actually think it is the typical solution rather than a work around. Alternatively Unity added the new Jobs system partly due to problems of the Unity API not being thread safe, but I don't think the Jobs system is appropriate for a TCP client/server thread replacement.
     
  5. maozao

    maozao

    Joined:
    Jan 20, 2016
    Posts:
    12
    Well, yeah, it is a solution, I just didn't like it that much, so not sure if there is a better way to handle that hehehehe

    By the way, I've checked the Job Sytem, and for sure it's not to be used in cases like this, seems just a way to process multiple things at same time (parallel) in different threads (low life threads), like rendering trees, walls, etc.
     
    Joe-Censored likes this.
  6. maozao

    maozao

    Joined:
    Jan 20, 2016
    Posts:
    12
    Any improvements in Unity about these kind of scenarios?
     
  7. mischa2k

    mischa2k

    Joined:
    Sep 4, 2015
    Posts:
    4,347
    Unity's GameObject world is not thread safe, you are supposed to access it only from the main thread.
    Unity's new DOTS/ECS can be threaded, but it's probably still too early to use.

    You can still use regular C# threads with GameObjects though. Just need to not access Unity API from the threads.
    For example, copy your data, push it into the thread with a ConcurrentQueue or similar, process in the thread, then push it back to main thread.

    Often the copy + queue overhead isn't worth putting it into a thread though.