Закрытие соединения и отписка от обработчика DataReceived - PullRequest
1 голос
/ 17 апреля 2019

У меня есть приложение, которое получает данные от внешнего лабораторного устройства через последовательный порт.Когда я пытаюсь закрыть SerialPort, я получаю следующую ошибку:

System.IO.IOException: «Операция ввода-вывода была прервана из-за выхода из потока или запроса приложения».

Данные читаются в обработчике событий, вызванные SerialPort event DataReceived - по умолчанию это выполняется в отдельном потоке (AFIK).

Я подписан на Eventhandler при установлении соединения с SerialPort.

Я отписываюсь от 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() я получаю:

'Операция ввода-вывода была прервана из-завыход из потока или запрос приложения. '

Ошибка генерируется из метода EventHandler SerialPort ReadTo(), даже если он отписался от обработчика событий непосредственно перед закрытием последовательного порта.

1 Ответ

0 голосов
/ 17 апреля 2019

Это потому, что вы используете SerialPort ReadTo, ReadTo блокируется, пока не увидит символ в указанном вами потоке буфера.Поэтому, когда вы собираетесь закрыть порт, ReadTo все еще ждет \r.Отмена подписки не достаточно, поскольку она все еще работает в своем собственном потоке.

Исправление будет заключаться в использовании ReadExisting(), который немедленно вернет все символы в буфере.Однако для этого потребуется больше логики на вашей стороне, в которой вам придется искать конечного персонажа самостоятельно.Ниже приведен простой способ использования 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);
        }
    }
}
...