关闭连接并取消订阅 DataReceived 处理程序
Closing connection and unsubscribing from DataReceived handler
我有一个应用程序可以通过串行端口从外部实验室单元接收数据。当我尝试关闭 SerialPort 时,出现以下错误:
System.IO.IOException: 'The I/O operation has been aborted because of either a thread exit or an application request.'
数据在事件处理程序中读取,由 SerialPort
事件引发 DataReceived
- 默认情况下在单独的线程中运行(AFIK)。
当与 SerialPort
建立连接时,我订阅了 Eventhandler
。
我在关闭串口之前退订了EventHandler
关闭连接的代码(其中 _chronosPort
是 SerialPort
的实例):
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()
方法时,我得到:
'The I/O operation has been aborted because of either a thread exit or an application request.'
错误是从 EventHandler
的 SerialPort ReadTo()
方法抛出的,即使在关闭串行端口之前已经取消订阅事件处理程序。
这是因为您正在使用 SerialPort
ReadTo
,ReadTo
一直处于阻塞状态,直到它在您指定的缓冲流中看到一个字符。所以当你去关闭端口的时候,ReadTo
还在等待一个\r
。取消订阅是不够的,因为它仍然 运行 在它自己的线程上。
修复方法是使用 ReadExisting()
,这将立即 return 缓冲区中的所有字符。但是,这将需要您这边有更多的逻辑,您必须自己寻找结束字符。下面是使用 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);
}
}
}
我有一个应用程序可以通过串行端口从外部实验室单元接收数据。当我尝试关闭 SerialPort 时,出现以下错误:
System.IO.IOException: 'The I/O operation has been aborted because of either a thread exit or an application request.'
数据在事件处理程序中读取,由 SerialPort
事件引发 DataReceived
- 默认情况下在单独的线程中运行(AFIK)。
当与 SerialPort
建立连接时,我订阅了 Eventhandler
。
我在关闭串口之前退订了EventHandler
关闭连接的代码(其中 _chronosPort
是 SerialPort
的实例):
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()
方法时,我得到:
'The I/O operation has been aborted because of either a thread exit or an application request.'
错误是从 EventHandler
的 SerialPort ReadTo()
方法抛出的,即使在关闭串行端口之前已经取消订阅事件处理程序。
这是因为您正在使用 SerialPort
ReadTo
,ReadTo
一直处于阻塞状态,直到它在您指定的缓冲流中看到一个字符。所以当你去关闭端口的时候,ReadTo
还在等待一个\r
。取消订阅是不够的,因为它仍然 运行 在它自己的线程上。
修复方法是使用 ReadExisting()
,这将立即 return 缓冲区中的所有字符。但是,这将需要您这边有更多的逻辑,您必须自己寻找结束字符。下面是使用 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);
}
}
}