C # Winform заморозить на SerialPort.Close - PullRequest
8 голосов
/ 13 января 2012

У меня есть программа winform, которая выполняет асинхронный ввод-вывод на SerialPort.Тем не менее, я периодически сталкиваюсь с проблемой зависания программы при вызове SerialPort.Close (), на первый взгляд случайным образом.

Я думаю, что это проблема безопасности потоков, но я не уверен, как ее исправить.это если это так.Я попытался добавить / удалить асинхронный обработчик DataReceived с помощью функций открытия / закрытия порта и отбросить входные и выходные буферы на порту, но, похоже, он ничего не делает.Я думаю, что важный SerialPort код находится ниже:

using System;
using System.Collections.Generic;
using System.IO.Ports;

public class SerialComm
{
  private object locker = new object();

  private SerialPort port;
  private List<byte> receivedBytes;

  public SerialComm(string portName)
  {
    port = new SerialPort(portName);
    port.BaudRate = 57600;
    port.Parity = Parity.None;
    port.DataBits = 8;
    port.StopBits = StopBits.One;

    receivedBytes = new List<byte>();
  }

  public void OpenPort()
  {
    if(port!=null && !port.IsOpen){
      lock(locker){
        receivedBytes.Clear();
      }

      port.DataReceived += port_DataReceived;
      port.Open();
    }
  }

  public void ClosePort()
  {
    if(port!=null && port.IsOpen){
      port.DataReceived -= port_DataReceived;
      while(!(port.BytesToRead==0 && port.BytesToWrite==0)){
        port.DiscardInBuffer();
        port.DiscardOutBuffer();
      }
      port.Close();
    }
  }

  private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
  {
    try{
      byte[] buffer = new byte[port.BytesToRead];
      int rcvdBytes = port.Read(buffer, 0, buffer.Length);

      lock(locker){
        receivedBytes.AddRange(buffer);
      }

      //Do the more interesting handling of the receivedBytes list here.

    } catch (Exception ex) {
      System.Diagnostics.Debug.WriteLine(ex.ToString());
      //put other, more interesting error handling here.
    }
  }
}

ОБНОВЛЕНИЕ

Благодаря ответу @ Afrin, указывающему на состояние тупика с потоком пользовательского интерфейса ( Этот пост в блоге хорошо описывает его и дает несколько других полезных советов), я сделал простое изменение и пока не смог воспроизвести ошибку!

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
  try{
    byte[] buffer = new byte[port.BytesToRead];
    int rcvdBytes = port.Read(buffer, 0, buffer.Length);

    lock(locker){
      receivedBytes.AddRange(buffer);
    }

    ThreadPool.QueueUserWorkItem(handleReceivedBytes);

  } catch (Exception ex) {
    System.Diagnostics.Debug.WriteLine(ex.ToString());
    //put other, more interesting error handling here.
  }
}

private void handleReceivedBytes(object state)
{
  //Do the more interesting handling of the receivedBytes list here.
}

Ответы [ 3 ]

15 голосов
/ 13 января 2012

Причина, по которой он зависает при закрытии, заключается в том, что в обработчике событий вашего объекта SerialPort

Вы синхронизируете вызов с основным потоком (как правило, вызывая invoke). Метод close SerialPort ожидает завершения потока EventLoopRunner, который запускает события DataReceived / Error / PinChanged. но поскольку ваш собственный код в событии также ожидает ответа основного потока, вы попадаете в ситуацию мертвой блокировки.

решение: используйте begininvoke вместо invoke: https://connect.microsoft.com/VisualStudio/feedback/details/202137/serialport-close-hangs-the-application

ссылка: http://stackoverflow.com/a/3176959/146622

0 голосов
/ 12 сентября 2018

У меня была такая же проблема. Я решил эту проблему с помощью библиотеки SerialPortStrem . Вы можете установить Nuget Pageckage Installer.

Библиотека SerialportStream имеет следующие преимущества.

  • Независимая реализация System.IO.Ports.SerialPort и SerialStream для повышения надежности и удобства обслуживания.

После использования библиотеки SerialPortStream у меня не было проблем с зависанием пользовательского интерфейса, таких как тупик в WPF. Я думаю, что та же проблема в формах Windows. Итак, используйте библиотеку SerialPortStream.

Эта библиотека, очевидно, является решением для решения проблемы зависания пользовательского интерфейса.

0 голосов
/ 06 августа 2018

Временное решение для пользователя nobugz из здесь :

1) добавить поле System.Threading.Thread CloseDown; в форму с последовательным портом serialPort1;

2) реализовать метод CloseSerialOnExit() с serialPort1 шаги закрытия:

private void CloseSerialOnExit()
{

    try
    {
        serialPort1.DtrEnable = false;
        serialPort1.RtsEnable = false;
        serialPort1.DiscardInBuffer();
        serialPort1.DiscardOutBuffer();
        serialPort1.Close();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);

    }
}

3) когда вам нужно закрыть serialPort1 (например, при нажатии кнопки), вызовите CloseSerialOnExit() в новой теме, чтобы избежать зависания:

...
CloseDown = new System.Threading.Thread(new System.Threading.ThreadStart(CloseSerialOnExit)); 
CloseDown.Start();
...

и все тут!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...