C# &引用;由于线程退出或应用程序请求,I/O操作已中止;关于断开串行通信

C# &引用;由于线程退出或应用程序请求,I/O操作已中止;关于断开串行通信,c#,exception,exception-handling,serial-port,C#,Exception,Exception Handling,Serial Port,我正在写一个程序,从串口读取数据并显示出来。有时(并非每次)当我断开串行连接时,由于线程退出或应用程序请求的原因,I/O操作被中止,出现异常时,它会崩溃。(我想这里有点不对劲,即使不是每次都发生) 以下是我如何阅读连载: private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) { // this line below is where the exception is

我正在写一个程序,从串口读取数据并显示出来。有时(并非每次)当我断开串行连接时,由于线程退出或应用程序请求的原因,I/O操作被中止,出现异常时,它会崩溃。(我想这里有点不对劲,即使不是每次都发生)

以下是我如何阅读连载:

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    // this line below is where the exception is
    string read = _serialPort.ReadLine().Replace(".", ",").Split('\r')[0];
}

// clicking on a button opens/closes serial
private void button1_Click(object sender, EventArgs e)
{
    if (isSerialConnected)
        disconnectSerial();
    else
        connectSerial();
}

public void connectSerial()
{
    _serialPort.PortName = serialCombobox.SelectedItem.ToString();
    _serialPort.BaudRate = 9600;
    _serialPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(this.serialPort1_DataReceived);
    _serialPort.Open();

    serialCombobox.Enabled = false;
    connectSerialButton.Text = "disconnect";

    isSerialConnected = true;
}

public void disconnectSerial()
{
   _serialPort.Close();

    serialCombobox.Enabled = true;
    connectSerialButton.Text = "connect";

    isSerialConnected = false;
}

我做错了什么?

从事件处理程序的串行端口读取数据。发件人:

默认情况下,ReadLine方法将阻塞,直到收到一行


因此,当您关闭串行端口时,可能仍在等待接收线路。但如果端口关闭,则无法接收数据,因此会引发异常,因为无法再接收行。

您从事件处理程序中的串行端口读取数据。发件人:

默认情况下,ReadLine方法将阻塞,直到收到一行


因此,当您关闭串行端口时,可能仍在等待接收线路。但是如果端口关闭,您将无法接收数据,因此会引发异常,因为无法再接收行。

我已将其更改为这种方式,现在这种方式可以正常工作

try
{
    read = _serialPort.ReadLine().Replace(".", ",").Split('\r')[0];
}
catch (System.IO.IOException error)
{
    return;
}
catch (System.InvalidOperationException error)
{
    return;
}
发生了两种错误,IOException和InvalidOperationException,分别出现在问题标题上的消息和消息“端口已关闭”。在这两种情况下,我们只返回数据,不处理数据


我不确定这是不是应该这样做,但无论如何,它有点工作。

我改变了这种方式,现在这种方式工作起来了

try
{
    read = _serialPort.ReadLine().Replace(".", ",").Split('\r')[0];
}
catch (System.IO.IOException error)
{
    return;
}
catch (System.InvalidOperationException error)
{
    return;
}
发生了两种错误,IOException和InvalidOperationException,分别出现在问题标题上的消息和消息“端口已关闭”。在这两种情况下,我们只返回数据,不处理数据


我不确定它是否应该这样做,但无论如何,它还是可以工作。

这是不可能的,SerialPort.Close()调用与DataReceived事件处理程序是互锁的。当事件处理程序仍在运行时,Close()无法继续。Crystal ball说你实际上用手猛拉了USB接口。切勿执行此操作,请始终查看“安全删除硬件托盘”图标。不清楚为什么要这样做,拔掉插头永远无法修复死锁。而是修复事件处理程序,永远不要调用Invoke(),而是始终开始调用Invoke()。还请记住,如果通信不可靠或未设置ReadTimeout属性而中断,ReadLine()是有风险的。@HansPassant不,我没有拔下它,我只是在应用程序中多次点击“连接/断开串行”按钮,最终导致异常happens@HansPassant我没有在处理程序中使用Invoke(),我只使用BeginInvoke在主线程中运行一些代码,但无论如何,如果我注释掉这段代码,将抛出异常。这是不可能的,SerialPort.Close()调用与DataReceived事件处理程序是互锁的。当事件处理程序仍在运行时,Close()无法继续。Crystal ball说你实际上用手猛拉了USB接口。切勿执行此操作,请始终查看“安全删除硬件托盘”图标。不清楚为什么要这样做,拔掉插头永远无法修复死锁。而是修复事件处理程序,永远不要调用Invoke(),而是始终开始调用Invoke()。还请记住,如果通信不可靠或未设置ReadTimeout属性而中断,ReadLine()是有风险的。@HansPassant不,我没有拔下它,我只是在应用程序中多次点击“连接/断开串行”按钮,最终导致异常happens@HansPassant我没有在处理程序中使用Invoke(),我只使用BeginInvoke在主线程中运行一些代码,但是无论如何,如果我注释掉这段代码,就会抛出异常。那么我应该如何处理呢?我想我可以将它包装在try/catch语句中,而在catch块中什么也不做,但是有些东西告诉我这不是应该怎么做的。在您的示例中,您无论如何都不使用
ReadLine
的结果,所以空的catch就可以了。您可能不希望出现
未处理的异常
事件。如果您能够以一种有用的方式处理异常,那就更好了。我至少建议记录该异常,以帮助将来进行诊断。然而,上面汉斯·帕桑的评论很有趣。这表明我的答案是错误的。或者可能在其他地方(驱动程序中?)有一个bug。实际上,我稍后会使用它,我只是将它注释掉,以查看带有ReadLine()的那一行是否确实是导致异常的原因。我应该如何处理它?我想我可以将它包装在try/catch语句中,而在catch块中什么也不做,但是有些东西告诉我这不是应该怎么做的。在您的示例中,您无论如何都不使用
ReadLine
的结果,所以空的catch就可以了。您可能不希望出现
未处理的异常
事件。如果您能够以一种有用的方式处理异常,那就更好了。我至少建议记录该异常,以帮助将来进行诊断。然而,上面汉斯·帕桑的评论很有趣。这表明我的答案是错误的。或者可能在其他地方(驱动程序中?)有一个bug。实际上,我稍后会使用它,我只是将它注释掉,看看带有ReadLine()的那一行是否真的是异常的原因
try
{
    read = _serialPort.ReadLine().Replace(".", ",").Split('\r')[0];
}
catch (System.IO.IOException error)
{
    return;
}
catch (System.InvalidOperationException error)
{
    return;
}