Тема: Передача даних між потоками
Привіт. Пишу клієнтську частину для ММО ЕрПоГе. Використовую двигун Unity3D, в принципі там той самий С# але структура скриптів своя. Коротше, дивіться яка схема. Для початку - в Юніті є свої методи, котрі можна запускати лишень в головному потоці. Ці методи відповідають за роботу з об'єктами в сцені  і так далі, наприклад,  створення в сцені об'єкту та присвоєння йому координат  необхідно робити в головному потоці. В скриптах Юніті є декілька важливих методів, це void Start, котрий являється чимось типу конструктора, він виконується до виконання інших скриптів, void Update, це метод, котрий виконується кожен фрейм. Так от, я використовую асинхронні сокети для взаємодії сервера та клієнта.  І, очевидно, данні приймаються методом, котрий виконується ну ніяк не в головному потоці. Тоді як ці дані передати в головний потік? Ну я зробив просто, створив List<byte[]>, і коли асинхронний метод приймає дані, то я заношу ці дані  в List, а в Update перевіряю, якщо в List щось є, то я витягую ці дані, та передаю на обробку в інший метод, а в тому методі, по закінченню всіх справ - я видаляю оброблені дані з List. Так от, ця схема і працює, але не ідеально, тому що не всі дані, котрі прийняв асинхронний метод, обробляються в методі, котрий викликається в Update. Яким ще чином можна організувати таку обробку даних? Ось код, щоб було зрозуміліше, зверніть увагу на методи ReceiveCallback та Update, перший приймає дані та заносить в чергу на обробку, а другий вже обробляє.
 p.s. це не windows forms, тому ніякі Invoke не спрацюють.
using UnityEngine;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System;
using System.Text;
using System.Linq;
using System.Collections.Generic;
 
public class client : MonoBehaviour {
       
        private GameObject player; 
        private Socket socket; 
        private byte[] buff; 
        private List<byte[]> listRec; 
        private characters iAm;
        //private List<byte[]> listSend;
        void Start () {
                socket=globalConnection.s;
                player = (GameObject)GameObject.FindGameObjectWithTag("Player"); 
                buff = new byte[4096]; 
                listRec=new List<byte[]>(); 
                //listSend=new List<byte[]>();
                iAm=globalConnection.activePlayer;
                SetActivePlayer(iAm);
                CreatePlayers(); 
        }
       
        void Update()
        {
                if(listRec.Count>0) 
                {
                        lock(listRec){
                        byte[] bf = listRec[listRec.Count-1]; 
                        ExecuteRec(bf); 
                        }
                }
                /*Debug.Log("count of global GO "+globalConnection.players.Count);
                foreach(var c in globalConnection.players)
                        Debug.Log(c);
                /*if(listSend.Count>0)
                {
                        StartCoroutine("ExecuteSend",listSend[listSend.Count-1]);
                }*/
        }
       
        byte[] PackPos()
        {
                float x,y,z,rx,ry,rz,rw;
                byte[] bf = new byte[64];
                int index=4; 
               
                int char_id=iAm.id; 
               
                x=player.transform.position.x;
                y=player.transform.position.y;
                z=player.transform.position.z;
               
                rx=player.transform.rotation.x;
                ry=player.transform.rotation.y;
                rz=player.transform.rotation.z;
                rw=player.transform.rotation.w;
               
                BitConverter.GetBytes(char_id).CopyTo(bf,index);
               
                BitConverter.GetBytes(x).CopyTo(bf,index+4);
                BitConverter.GetBytes(y).CopyTo(bf,index+8);
                BitConverter.GetBytes(z).CopyTo(bf,index+12);
               
                BitConverter.GetBytes(rx).CopyTo(bf,index+16);
                BitConverter.GetBytes(ry).CopyTo(bf,index+20);
                BitConverter.GetBytes(rz).CopyTo(bf,index+24);
                BitConverter.GetBytes(rw).CopyTo(bf,index+28);
               
                Encoding.UTF8.GetBytes("man").CopyTo(bf,0); 
                return bf;
        }
       
        void ExecuteRec(byte[] b)
        {
                string req = Encoding.UTF8.GetString(b,0,3);
                switch(req)
                {
                case "man" :
                        SetMain(b); 
                        Debug.Log("Receive man");
                        break;
                case "act" :
                        CreateChar(b);
                        Debug.Log("Act");
                        break;
                }
                lock(listRec)
                {
                listRec.Remove(b); 
                }               //yield return 0;
 
        }
       
        IEnumerator Sending()
        {
                while(true){ 
                byte[] bf = PackPos(); 
                        try{
                socket.BeginSend(bf,0,bf.Length,SocketFlags.None,new AsyncCallback(SendCallback),socket);
                        }
                        catch(Exception e)
                        {
                                Debug.Log("Sending "+e.Message);
                        }
                yield return new WaitForSeconds(1); 
                }
        }
       
        void CreatePlayers()
        {
                if(globalConnection.activePlayers.Count>0) 
                {
                        GameObject go = (GameObject)Resources.Load("Players"); 
                        foreach(var pl in globalConnection.activePlayers)
                        {
                                GameObject g = (GameObject)Instantiate(go); 
                                PlayerManager pm = (PlayerManager)g.GetComponent("PlayerManager"); 
                                pm.Construct(pl.name,pl.id,pl.x,pl.y,pl.z); 
                                globalConnection.players.Add(pm);                        }
                }
                socket.BeginReceive(buff,0,buff.Length,SocketFlags.None,new AsyncCallback(ReceiveCallback),socket); 
                StartCoroutine("Sending");
        }
        void CreateChar(byte[] b)
        {
 
                float x = BitConverter.ToSingle(b,20);
                float y = BitConverter.ToSingle(b,24);
                float z = BitConverter.ToSingle(b,28);
                string nick = Encoding.UTF8.GetString(b,10,20);
                int id = BitConverter.ToInt32(b,4);
                GameObject go = (GameObject)Resources.Load("Players");
                lock(globalConnection.players)
                {
                        GameObject g = (GameObject)Instantiate(go);
                        PlayerManager pm = (PlayerManager)g.GetComponent("PlayerManager");
                        pm.Construct(nick,id,x,y,z);
                        globalConnection.players.Add(pm);
                }
        }
        void SetMain(byte[] b)
        {      
                int char_id= BitConverter.ToInt32(b,4); 
                Debug.Log("char_id = "+char_id);
                foreach(var pm in globalConnection.players) 
                {
                        //PlayerManager pm = (PlayerManager)ch.GetComponent("PlayerManager");
                        if(pm.id==char_id)
                        {
                                int index=4;
                        float x = BitConverter.ToSingle(b,index+4);
                        float y = BitConverter.ToSingle(b,index+8);
                        float z = BitConverter.ToSingle(b,index+12);
                        float rx = BitConverter.ToSingle(b,index+16);
                        float ry = BitConverter.ToSingle(b,index+20);
                        float rz = BitConverter.ToSingle(b,index+24);
                        float rw = BitConverter.ToSingle(b,index+28);
                                pm.transform.position=new Vector3(x,y,z);
                                pm.transform.rotation=new Quaternion(rx,ry,rz,rw);
                                Debug.Log("Set: x="+x+" y="+y+" z="+z);
                        }
                }
 
        }
       
        void SetActivePlayer(characters ch)
        {
                byte[] bf = new byte[32];
                Encoding.UTF8.GetBytes("act").CopyTo(bf,0);
                BitConverter.GetBytes(ch.id).CopyTo(bf,3);
                Encoding.UTF8.GetBytes(ch.name).CopyTo(bf,10);
                socket.BeginReceive(buff,0,buff.Length,SocketFlags.None,new AsyncCallback(ReceiveCallback),socket);
                socket.BeginSend(bf,0,bf.Length,SocketFlags.None,new AsyncCallback(SendCallback),socket);
        }
       
        void SendCallback(IAsyncResult ar)
        {
                Socket s = (Socket)ar.AsyncState;
                try{
                        s.EndSend(ar);
                }
                catch(Exception e)
                {
                        Debug.Log(e.Message);
                }
        }
       
        void ReceiveCallback(IAsyncResult ar)
        {
                Debug.Log("Receive from client");
                Socket s = (Socket)ar.AsyncState;
                string ss = Encoding.UTF8.GetString(buff,0,3);
                try{
                        int n = s.EndSend(ar);
                        lock(listRec){
                        listRec.Add(buff);
                        }
                        Debug.Log("ReceiveCallback "+n+" with command = "+ss); 
                }
                catch(Exception e)
                {
                        Debug.Log("ReceiveCallback "+e.Message);
                        s.Close();
                }
                s.BeginReceive(buff,0,buff.Length,SocketFlags.None,new AsyncCallback(ReceiveCallback),s);
        }
 
}