在没有调度程序的情况下从工作人员更新主线程

时间:2014-05-26 14:56:58

标签: c# multithreading unity3d thread-safety

之前可能已经提到过,但我找不到正确的答案。

我有一个dll,它在自己的线程中运行一个管道。我在Unity项目中使用该DLL,但是我推送到Unity的消息最终都是异常,因为我没有从主线程调用它们。所以我需要一些帮助来实现这一权利。以下是我启动后台工作者的方法:

var worker = new BackgroundWorker();
        worker.DoWork += (sender, e) =>
        {
            var client = new NamedPipeClientStream(".", "kinect-pipe", PipeDirection.In);
            client.Connect();

            while (_isWorkerRunning)
            {
                using (var sr = new StreamReader(client))
                {
                    string temp;
                    while ((temp = sr.ReadLine()) != null)
                    {
                        // TODO send message to Unity in main thread
                    }
                }

                if (!client.IsConnected)
                {
                    client.Connect();
                }
            }

            client.Flush();
            client.Close();
            client.Dispose();
        };
        worker.RunWorkerAsync();

我的管道客户端在一个线程中运行,我有一个公共事件,它向Unity发送消息。但我需要确保分派消息。而且我不确定如何以正确的方式做到这一点?

2 个答案:

答案 0 :(得分:0)

我找到了一个简单的解决方案,我在线程中使用共享缓冲区。所以我的管道看起来像这样:

    private void PipeClientWorker()
    {
        //Client
        var client = new NamedPipeClientStream(".", "kinect-pipe", PipeDirection.In);
        client.Connect();

        while (_isWorkerRunning)
        {
            using (var sr = new StreamReader(client))
            {
                string temp;
                while ((temp = sr.ReadLine()) != null)
                {
                    // TODO figure out how to do this in the right thread
                    if (KinectHandler != null)
                    {
                        KinectHandler.BeginInvoke(temp, null, null);
                    }
                }
            }

            if (!client.IsConnected)
            {
                client.Connect();
            }
        }

        client.Flush();
        client.Close();
    }

我正常地开始:

var thread = new Thread(PipeClientWorker) {Name = "Pipe Worker Thread", IsBackground = true};
thread.Start();

在Unity中,我创建了一个将消息放入堆栈的KinectController,并在Update循环中将它们弹出到一个LastMessage字符串中:

public string LastMessage;

private KinectReader _kinectReader;
private volatile Stack<string> _messageStack;


// Use this for initialization
void Start () 
{
    _messageStack = new Stack<string>();
    LastMessage = "";

    // init Kinect Reader
    _kinectReader = new KinectReader();
    _kinectReader.StartPipeReader();
    _kinectReader.KinectHandler += _kinectReader_KinectHandler;
}

void _kinectReader_KinectHandler(string message)
{
    _messageStack.Push(message);
}

// Update is called once per frame
void Update () 
{
    // Update Last message
    while (_messageStack.Any())
    {
        LastMessage = _messageStack.Pop();
        Debug.Log(LastMessage);
    }
}

void OnApplicationQuit()
{
    Debug.Log("Stoping the pipe client");
    _kinectReader.Stop();
    Debug.Log("Qutting application");
}

如果有人有类似的问题或解决了不同的问题,我想讨论解决方案:)

答案 1 :(得分:0)

试试Thread Ninja。有了它,您可以以协程风格运行后台作业。