【问题标题】:Processing received UDP data in another thread in C#在 C# 的另一个线程中处理接收到的 UDP 数据
【发布时间】:2013-06-19 13:51:32
【问题描述】:

我有一个类,它包含一个在单独的线程中接收 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
    }

}

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

【问题讨论】:

  • 为什么不简单地:OnNewData(data) + 一些Invoke?抱歉,如果我遗漏了什么……Unity 有什么特别之处吗?
  • @Pragmateek 我将如何调用该方法?我的线程知识非常有限。
  • 您可能遇到的唯一问题是使用 线程关联 更新某些 UI 组件,这需要使用特殊方法将您的处理推入 UI 线程队列,否则这是就像调用方法一样简单:byte[] data = (m_UDPClient.Receive(ref anyIP)); networkController.OnNewData(data);
  • 这不会还在同一个子线程中运行吗? NetworkController 应该和 UDPReceiver 在同一个线程中运行,而不是 UDPReceiver 启动的子线程。
  • 你为什么要这么做? :) 正如我所说,您想要使用特定线程的唯一原因之一是线程关联。试一试,检查一切正常。 :)

标签: c# multithreading udp unity3d


【解决方案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();
    }
}

【讨论】:

  • Unity 最多只支持 Mono 2.6(我相信是 .net 3.5),而且只是其中的一个子集。对于我们可怜的 Unity 用户来说,这意味着没有 BlockingCollections。
  • @Jerdak:我已经更新了我的答案,应该适用于你的古董版本;)
  • 你能把更新传真给我吗? :) 其他用户需要注意的一件事:如果工作线程分配任务的速度快于task() 可以执行的速度,则此代码最终可能会锁定 Unity 的主线程。
  • 是的,所以如果您愿意,您可以使用更精细的执行策略:一次只执行一个,让其他行为有机会运行。我会更新...
  • 请注意,在您的情况下,如果没有其他线程正在读取队列,您可以避免第二个 if (tasks.Count != 0)。
猜你喜欢
  • 1970-01-01
  • 2013-09-08
  • 2019-10-13
  • 2013-03-29
  • 2016-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多