Igor Juric
Igor Juric

Reputation: 23

Closing connection and unsubscribing from DataReceived handler

I have an application that receives the data from an external laboratory unit trough a serial port. When I try to close the SerialPort, I get the following error:

System.IO.IOException: 'The I/O operation has been aborted because of either a thread exit or an application request.'

The data is read in event handler, raised by SerialPort event DataReceived - this runs in a separate thread by default (AFIK).

I subscribe to the Eventhandler when connection to a SerialPort is being established.

I unsubscribe from the EventHandler before I close the serial port.

Code to close the connection (where _chronosPort is an instance of a 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());
}

When invoking the Close() method, I get:

'The I/O operation has been aborted because of either a thread exit or an application request.'

The error is thrown from EventHandler's SerialPort ReadTo() method, even though have unsubscribed from the event handler just before closing the serial port.

Upvotes: 2

Views: 967

Answers (1)

Baddack
Baddack

Reputation: 2053

It's because you are using SerialPort ReadTo, the ReadTo is blocking until it see's a character in the buffer stream you specified. So when you go to close the port, the ReadTo is still waiting for a \r. Unsubscribing isn't enough, as it's still running on it's own thread.

The fix would be to use ReadExisting(), which will return all the characters in the buffer immediately. However, this will require more logic on your side in which you'll have to look for that end character yourself. Below is a simple way to use ReadExisting, I build the string until I see my end character then I parse the string:

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);
        }
    }
}

Upvotes: 1

Related Questions