Windows создается с SerialPort - приложение зависает после закрытия формы - PullRequest
1 голос
/ 07 ноября 2019

У меня есть приложение Windows Form для подключения к плате Arduino. когда я хочу закрыть его, он остается открытым, пока я не остановлю режим отладки. это происходит, когда я запускаю программу в Visual Studio и когда я запускаю только файл exe, мне нужно остановить его из диспетчера задач.

Я пытался и FormClosing, и FormClosed события, но результат тот же. единственное, что пришло мне в голову, это то, что эта проблема возникает из-за того, что я использовал много функций Invoke для своих элементов управления в событии DataRecieved моего SerialPort. Я сделал это, потому что мне нужны потокобезопасные вызовы для моих элементов управления формой. Вот некоторая часть моего кода:

private void spArduino_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
  if (spArduino.BytesToRead > 0)
  {
     string data = spArduino.ReadLine().Replace("\r", "");
     if (data.StartsWith("CUR_TEMP:"))
     {
         if (lbTemprature.InvokeRequired)
         {
            lbTemprature.Invoke(new MethodInvoker(delegate {
               lbTemprature.Text = "Room temprature  " + data.Remove(0,9) + "°C";
             }));
         }
     }
  }
}
///////
 private void Monitoring_FormClosing(object sender, FormClosingEventArgs e)
 {
     try
     {
          spArduino.WriteLine("CLEAR");
          spArduino.Close();
     }
     catch (Exception)
     {
          MessageBox.Show("errorclose");
     }
 }

И это проявляется в моем выводе (Visual Studio)

The thread 0x2bf0 has exited with code 0 (0x0).
The thread 0x5f24 has exited with code 0 (0x0).
The thread 0x46c4 has exited with code 0 (0x0).
The thread 0x5df4 has exited with code 0 (0x0).
The thread 0x294c has exited with code 0 (0x0).
The thread 0x4620 has exited with code 0 (0x0).
The thread 0x720 has exited with code 0 (0x0).
The thread 0x35a0 has exited with code 0 (0x0).

И так будет до тех пор, пока я не остановлю программу.

Может кто-нибудь помочь мне понять, где моя проблема и как я могу ее решить?

Ответы [ 2 ]

0 голосов
/ 07 ноября 2019

Событие SerialPort.DataReceived инициируется в отдельном потоке, отличном от основного потока пользовательского интерфейса, поэтому при обновлении пользовательского интерфейса необходимо вызывать метод lbTemprature.Invoke.

Закрытие формы без закрытия порта

Если вы закрываете форму, не закрывая порт, то при закрытии формы может возникнуть событие DataReceived после удаления формы, что вызовет исключение при попытке обновить пользовательский интерфейс.

Закрытие порта до закрытия формы

Если закрыть порт до закрытия формы (например, в событии FormClosing), вы можете столкнуться с тупиковой блокировкой, поскольку SerialPort.Close() вОсновной поток пользовательского интерфейса ожидает поток, который запускает событие DataReceived для завершения события, а событие DataReceived ожидает потока пользовательского интерфейса при вызове lbTemprature.Invoke. Вероятно, именно это приводит к зависанию формы.

Решение

Решением может быть вызов lbTemprature.BeginInvoke, чтобы избежать тупиковой блокировки. Этого может быть недостаточно, поскольку BeginInvoke все еще может работать после удаления формы и вызывать ожидание. Добавление чека к свойству Form.IsDisposed может потребоваться.

if (lbTemprature.InvokeRequired)
{
    lbTemprature.BeginInvoke(new MethodInvoker(delegate
    {
        if (!this.IsDisposed)
        {
            lbTemprature.Text = "Room temprature  " + data.Remove(0,9) + "°C";
        }
    }));
}
0 голосов
/ 07 ноября 2019

Посмотрите, как вы чистите последовательное устройство. Попробуйте отказаться от подписки на событие (я) (т.е. -= spArduino_DataReceived). Вполне возможно, что ссылки не позволяют собирать мусор и поддерживают вашу форму после закрытия.

...