关闭连接并取消订阅DataReceived处理程序

时间:2019-04-17 13:37:33

标签: c# serial-port eventhandler

我有一个应用程序,它通过串行端口从外部实验室单元接收数据。当我尝试关闭SerialPort时,出现以下错误:

  

System.IO.IOException:'由于线程退出或应用程序请求,I / O操作已中止。'

在事件处理程序中读取数据,由SerialPort事件DataReceived引发-默认情况下,该数据在单独的线程(AFIK)中运行。

Eventhandler建立连接后,我订阅了SerialPort

在关闭串行端口之前,我要退订EventHandler

关闭连接的代码(其中_chronosPortSerialPort的实例):

public void CloseConnection()
{
    if (_connected)
    {
        _chronosPort.DataReceived -= OnDataReceived;
        _chronosPort.Close();
        _connected = false;
     }
 }

private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
{
     var sp = (SerialPort) sender;
     RawSample = sp.ReadTo("\r");
     SampleFactory sampleFactory = new SampleFactory(RawSample, new SampleTypeExtractor());
     OnSampleReady(sampleFactory.GetSample());
}

调用Close()方法时,我得到:

  

“由于线程退出或应用程序请求,I / O操作已中止。”

EventHandler的{​​{1}}方法引发了错误,即使在关闭串行端口之前已取消订阅事件处理程序。

1 个答案:

答案 0 :(得分:0)

这是因为您正在使用SerialPort ReadToReadTo一直阻塞,直到在您指定的缓冲流中看到一个字符为止。因此,当您关闭端口时,ReadTo仍在等待\r。取消订阅是不够的,因为它仍在自己的线程上运行。

解决方法是使用ReadExisting(),它将立即返回缓冲区中的所有字符。但是,这将需要您方面的更多逻辑,您必须自己寻找该最终角色。以下是使用ReadExisting的简单方法,我先构建字符串,直到看到结束符,然后解析字符串:

StringBuilder sb = new StringBuilder();

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    string Data = serialPort1.ReadExisting();

    foreach (char c in Data)
    {
        if (c == '\r')
        {
            sb.Append(c);

            CurrentLine = sb.ToString();
            sb.Clear();

            SampleFactory sampleFactory = new SampleFactory(CurrentLine, new SampleTypeExtractor());
            OnSampleReady(sampleFactory.GetSample());
        }
        else
        {
            sb.Append(c);
        }
    }
}