C# 串行通信自定义函数,首次调用后 AutoResetEvent 超时

问题描述 投票:0回答:1

我正在尝试使用串行通信与定制硬件进行通信。硬件具有内置方法,可以通过命令调用。

要发送命令并读取函数的输出(从硬件),我使用

AutoResetEvent
事件,如下所示:

private string receiveMessage(string command)
{
    string rxMessage = "Error";

    var mre = new AutoResetEvent(false);
    var buffer = new StringBuilder();

    serialPort.DataReceived += (s, e) =>
    {
        buffer.Append(serialPort.ReadExisting());
        if (buffer.ToString().IndexOf("\r\n") >= 0)
        {
            rxMessage = buffer.ToString();

            mre.Set();
            buffer.Clear();
        }
    };

    var responseTimeout = TimeSpan.FromSeconds(10);

    try
    {
        serialPort.WriteLine(command);
        if (!mre.WaitOne(responseTimeout))
        {
            rxMessage = "Did not receive response";
        }
    }
    catch (TimeoutException)
    {
        rxMessage = "Write took longer than expected";
    }
    catch
    {
        rxMessage = "Failed to write to port";
    }

    return rxMessage;
}

此方法在第一次调用时就可以完美运行。但是,如果第二次调用,串口超时,该方法返回“未收到响应”。

我是否遗漏了什么或者我错误地创建了

receieveMessage()
方法?

非常感谢。

c# serial-port serial-communication autoresetevent
1个回答
0
投票

这很可能是由于未取消注册事件处理程序造成的。因此,当您第二次调用

receiveMessage
时,您将不得不使用不同的事件处理程序。第一个将读取所有数据并设置其自动重置事件。当调用第二个事件处理程序时,没有数据可读取,并且其自动重置事件将超时。

要解决这个问题,您有几种选择。一种是注销事件处理程序。为此,您需要将 lambda 转换为委托对象,即

SerialDataReceivedEventHandler myHandler = (s, e) => {...}
 serialPort.DataReceived += myHandler ;
...
serialPort.DataReceived -= myHandler ;

或者将 lambda 替换为 本地函数

另一种选择是将方法更改为类,这样您只需注册一次 DateReceived 事件。

请注意,我认为你有竞争条件。如果在调用

WaitOne
之前接收到数据,则不会设置该事件,并且您将超时。使用 ManualResetEvent/ManualResetEventSlim 保持信号状态直到显式重置应该可以避免此问题。

© www.soinside.com 2019 - 2024. All rights reserved.