我正在使用SerialPort对象通过USB与外部设备进行通信。我遇到一个问题,其中Close()方法似乎抛出一个System.IO.IOException,它没有被周围的catch块捕获并导致程序锁定。
这是我收到的调试信息:
The thread '<No Name>' (0x1c0c) has exited with code 0 (0x0).
A first chance exception of type 'System.IO.IOException' occurred in System.dll
A first chance exception of type 'System.IO.IOException' occurred in System.dll
这是代码的具体摘录:
Try
_connOpen = False
RemoveHandler serialPort.DataReceived, AddressOf serialPort_DataReceived
serialPort.RtsEnable = False
serialPort.DtrEnable = False
Application.DoEvents()
serialPort.DiscardInBuffer() ' clear input buffer
serialPort.Close() ' close the port
MyBase.OnConnectionChanged(EventArgs.Empty)
Catch ex As IOException
Debug.Print("Exception caught")
serialPort.Dispose()
serialPort = Nothing
End Try
尽管调试告诉我抛出了IOException,但从未输入Catch块。我使用断点跟踪此行的异常。
答案 0 :(得分:2)
似乎抛出了一个System.IO.IOException,它没有被周围的catch块
捕获
正在处理 ,您只看到“第一次机会”通知,而不是“异常未处理”消息。这些异常发生在工作线程上,SerialPort开始生成DataReceived,ErrorReceived和PinChanged事件。
你得到这个是因为你在接收数据时关闭了端口,设置DtrEnable = False只能在你给串行设备时间看信号变化时才能工作,你不要等待足够长的时间。 DoEvents()是危险的,并没有修复它,因为它只延迟了〜微秒,你需要一秒钟才能确定。激活USB连接器然后尝试关闭端口是另一种触发异常的好方法,很少有USB设备驱动程序能够顺利处理这种情况。
并导致程序锁定
这是你真正的问题。当您在接收数据时关闭端口并在DataReceived事件处理程序中出错时,SerialPort.Close()将死锁。在事件处理程序停止运行之前,端口无法关闭。标准错误是在事件处理程序中使用Control.Invoke()
,通常使用,因为您无法从工作线程更新UI。但这是一种非常危险的方法,很容易造成死锁。在UI线程空闲之前,它无法完成。它不是空闲的,它停留在Close呼叫中。在事件处理程序停止运行之前无法完成。它不会停止运行,它会停留在Invoke()调用中。死锁城市。
始终使用Control.BeginInvoke()
代替,它不会导致死锁。在另一个线程上调用Close()也是一个创可贴。
答案 1 :(得分:1)
当您拨打serialPort.Close()
时,您实际上正在呼叫serialPort.Dispose()
。来自反射器:
Public Sub Close()
MyBase.Dispose
End Sub
要捕获异常,您需要将serialPort.Dispose()
放在catch块中;
Try
'...
serialPort.Close()
'...
Catch ex As IOException
Debug.Print("Exception caught")
End Try
或者您可以通过查看Open
状态来执行此操作:
Try
'...
serialPort.Close()
'...
Catch ex As IOException
Debug.Print("Exception caught")
If ((Not serialPort Is Nothing) AndAlso serialPort.IsOpen) Then
serialPort.Close()
serialPort = Nothing
End If
End Try
答案 2 :(得分:0)
我解决方案我发现其他似乎工作的地方是有一个标志来关闭端口
closePort = True
然后在收到的数据上检查标志并关闭端口:
Private Sub serialPort_DataReceived(sender As Object, e As SerialDataReceivedEventArgs) Handles serialPort.DataReceived
If closePort Then
serialPort.Close()
Else
readSerialPortData()
End If
End Sub