0

我有一个类,它包含一个在单独的线程中接收 UDP 数据的方法。我这样做是为了避免主应用程序(在 Unity3D 中运行)停止。

我需要将在单独线程中接收到的数据传递给另一个类,该类在原始线程上运行,因此能够与 Unity3D 交互。

UDPReceiver 大致如下所示:

public class UDPReciever {

    //...

    public UDPReciever() {
        m_Port = 12345;
        m_Worker = new Thread(new ThreadStart(recvData));
        m_Worker.IsBackground = true;
        m_Worker.Start();
    }

    void recvData() {
        m_UDPClient = new UdpClient(m_Port);
        while (true) {
            try {
                IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
                byte[] data = (m_UDPClient.Receive(ref anyIP));  

                // TODO: Hand 'data' to NetworkController class (running in the original thread) for processing

            } catch (Exception err) {
                    print(err.ToString());
            }
        }
    }   

}

这大致就是 NetworkController 类需要的样子。理想情况下,每次接收到带有作为参数传递的数据的新数据包时都会调用“OnNewData”方法。

public class NetworkController {

    //...

    void OnNewData(pData) {
        // Process the data in this thread
    }

}

我将如何实现这一目标?提前致谢。

4

1 回答 1

1

这是如何完成的(未测试):

public class Dispatcher : MonoBehaviour
{       
    private static readonly BlockingCollection<Action> tasks = new BlockingCollection<Action>();

    public static Dispatcher Instance = null;

    static Dispatcher()
    {
        Instance = new Dispatcher();
    }

    private Dispatcher()
    {
    }

    public void InvokeLater(Action task)
    {
        tasks.Add(task);
    }

    void FixedUpdate()
    {
        if (tasks.Count > 0)
        {
            foreach (Action task in tasks.GetConsumingEnumerable())
            {
                task();
            }
        }
    }
}
...
NetworkController networkControllerInstance;

void recvData()
{
    m_UDPClient = new UdpClient(m_Port);
    while (true)
    {
        try
        {
            IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
            byte[] data = (m_UDPClient.Receive(ref anyIP));  

            Dispatcher.Instance.InvokeLater(() => networkControllerInstance.OnNewData(data));
        }
        catch (Exception err)
        {
            print(err.ToString());
        }
    }
}

编辑:

应符合.Net 3.5的版本:

public class Dispatcher : MonoBehaviour
{       
    private static readonly Queue<Action> tasks = new Queue<Action>();

    public static Dispatcher Instance = null;

    static Dispatcher()
    {
        Instance = new Dispatcher();
    }

    private Dispatcher()
    {
    }

    public void InvokeLater(Action task)
    {
        lock (tasks)
        {
            tasks.Enqueue(task);
        }
    }

    void FixedUpdate()
    {
        while (tasks.Count > 0)
        {
            Action task = null;

            lock (tasks)
            {
                if (tasks.Count > 0)
                {
                    task = tasks.Dequeue();
                }
            }

            task();
        }
    }
}

编辑2:

如果您想避免在太长时间内冻结主线程:

void FixedUpdate()
{
    if (tasks.Count != 0)
    {
        Action task = null;

        lock (tasks)
        {
            if (tasks.Count != 0)
            {
                task = tasks.Dequeue();
            }
        }

        task();
    }
}
于 2013-06-19T19:47:32.783 回答