Search Unity

Begin/EndInvoke not synchronizing with Unity's main thread

Discussion in 'Scripting' started by forteller, Aug 4, 2020.

  1. forteller

    forteller

    Joined:
    Jun 15, 2019
    Posts:
    55
    I'm creating a networked game using tcp based sockets.
    (I'm new to networking and threading stuff).

    I'm using System.Net.Sockets async methods like socket.BeginReceive() and socket.EndReceive().
    All the client-server connecting and messaging works. But as soon as I try access anything from a Monobehavior (so that I can actually have any effect on the Unity game), like a gameobject's transform, an exception is thrown telling me that I can only access these properties from the main thread.

    My question is why am I not back on the main thread after I call foo.EndReceive()? How do I return to the mainthread using the async socket api? Will I end up having to use the synchronous socket api and just handle the threading myself so I can properly resync with Unity's main thread?

    Thanks!

    My hunch is that the problem is occurring because of the way in which i set up the beginInvoke() callbacks recursively... in that i setup the begininvoke callback inside the beginInvoke callback which perhaps isn't executed on the mainthread??? I'm not sure.... Any help would be much appreciated.



    Code (CSharp):
    1.  
    2. //code which sets up the callbacks which are executed when a client receives a message from the server
    3. void BeginReceive() => _clientSocket.BeginReceive(_messageReceivedBuffer, 0, _messageReceivedBuffer.Length, SocketFlags.None, ReceiveCallback, null);
    4.  
    5. void ReceiveCallback(IAsyncResult result)
    6.         {
    7.             _clientSocket.EndReceive(result);
    8.  
    9.             var msg = _serializer.ByteArrayToObject<NetworkMessage>(_messageReceivedBuffer);
    10. //this clientmanipulation manipulates the game grid and the gameobjects' which it references
    11. //it's in this method that an exception gets thrown and the code breaks
    12.             msg.ClientManipulation(_gameGrid);
    13.          
    14.             BeginReceive();
    15.         }
     
  2. alexzzzz

    alexzzzz

    Joined:
    Nov 20, 2010
    Posts:
    1,447
    A possible solution:

    Read the current thread synchronization context while you are in the main thread
    Code (CSharp):
    1. SynchronizationContext mainThreadContext = SynchronizationContext.Current;
    Then use it to execute your code on the main thread using its Send (synchronous execution) or Post (asynchronous execution) methods
    Code (CSharp):
    1. mainThreadContext.Post(_ => Debug.Log("Hello, World!"), null);
     
    forteller likes this.
  3. TheZombieKiller

    TheZombieKiller

    Joined:
    Feb 8, 2013
    Posts:
    266
    This is what I also do whenever I need to schedule work on the main thread. It'd be nice if Unity provided a more formal accessor for it, since at present I just cache it using a [RuntimeInitializeOnLoadMethod]-marked function.