문제

I am using a SerialPort object for communication over USB with an external device. I am experiencing an issue where the Close() method seems to be throwing a System.IO.IOException which is not being caught by a surrounding catch block and causing the program to lock up.

This is the debug message I'm getting:

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

This is the specific extract of code:

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

The Catch block is never entered despite debug telling me an IOException being thrown. I've track the exception to this line using breakpoints.

도움이 되었습니까?

해결책 3

I solution I found somewhere else which seems to work is to have a flag to close the port

closePort = True

Then on data received check the flag and close the port:

Private Sub serialPort_DataReceived(sender As Object, e As SerialDataReceivedEventArgs) Handles serialPort.DataReceived
    If closePort Then
        serialPort.Close()
    Else
        readSerialPortData()
    End If
End Sub

다른 팁

seems to be throwing a System.IO.IOException which is not being caught by a surrounding catch block

It is being handled, you only see the "first chance" notification, not an "Exception was unhandled" message. These exceptions occur on a worker thread that SerialPort starts to generate the DataReceived, ErrorReceived and PinChanged events.

You get this because you close the port while it is receiving data, setting DtrEnable = False can only work when you give the serial device time to see the signal change, you don't wait nearly long enough for that. DoEvents() is dangerous and doesn't fix it because it only delays for a ~microsecond, you need a second to be sure. Jerking the USB connector and then trying to close the port is another good way to trigger exceptions, there are very few USB device drivers that handle this smoothly.

and causing the program to lock up

This is your real problem. SerialPort.Close() will deadlock when you close the port while it is receiving data and made a mistake in your DataReceived event handler. The port cannot close until your event handler stops running. The standard mistake is using Control.Invoke() in your event handler, typically used because you can't update the UI from a worker thread. But that's a very dangerous method, it is very apt to cause deadlock. It cannot complete until your UI thread goes idle. It isn't idle, it is stuck in the Close call. Which cannot complete until your event handler stops running. It won't stop running, it is stuck in the Invoke() call. Deadlock city.

Always use Control.BeginInvoke() instead, it cannot cause deadlock. Calling Close() on another thread is a band-aid as well.

When you call serialPort.Close() you're actually calling serialPort.Dispose(). From reflector:

Public Sub Close()
    MyBase.Dispose
End Sub

To catch the exception you'll need to drop the serialPort.Dispose() in the catch block;

Try
    '...
    serialPort.Close()
    '...
Catch ex As IOException
    Debug.Print("Exception caught")
End Try

Or you might do it by checking the Open state:

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
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top