Possiedo un programma Winform che esegue un IO asincrono su un SerialPort
. Tuttavia, sto periodicamente incontrando un problema con il blocco del programma sulla chiamata SerialPort.Close(), apparentemente a caso.C# Winform si blocca su SerialPort.Close
Penso che sia un problema di sicurezza dei thread, ma non sono sicuro di come risolverlo se lo è. Ho provato ad aggiungere/rimuovere il gestore DataReceived asincrono con le funzioni di apertura/chiusura della porta e scartare i buffer in e out sulla porta, ma non sembra fare nulla. Credo che il codice importante SerialPort
è qui sotto:
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.
}
}
}
UPDATE
Grazie a @ risposta di Afrin sottolineando la condizione di stallo con il thread UI (This blog post fa un buon lavoro che descrive, e dà molti altri buoni consigli), ho apportato un semplice cambiamento e non sono ancora riuscito a riprodurre l'errore!
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.
}
Per assicurarsi ho capito bene, in sintesi, c'è una situazione di stallo all'interno della 'SerialPort' tra il' Read' e la Chiamate 'Close'? – chezy525
è necessario modificare il modo in cui si richiamano gli aggiornamenti degli elementi dell'interfaccia utente nel gestore eventi port_DataReceived, utilizzare BeginInvoke per aggiornare anziché Invoke oppure, come descritto nella soluzione, utilizzare un altro thread per gestire l'evento. – Afshin
La gestione dei dati per l'interfaccia utente su un thread diverso sembra aver risolto il problema. Grazie! – chezy525