Mam program WinForm, który wykonuje niektóre asynchroniczne IO na SerialPort
. Jednak od czasu do czasu napotykam na problem z zamrożeniem programu w wywołaniu SerialPort.Close(), pozornie losowym.C# Winmost zamrażanie na SerialPort.Close
Myślę, że to kwestia bezpieczeństwa wątków, ale nie jestem pewien, jak to naprawić, jeśli tak jest. Próbowałem dodać/usunąć asynchroniczną procedurę obsługi DataReceived z funkcjami otwierania/zamykania portów i odrzucania buforów wejściowych i wyjściowych na porcie, ale nie wydaje się, aby to działało. Myślę, że ważny kod SerialPort
jest poniżej:
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
Dzięki @ odpowiedź Afrin za wskazując stan zakleszczenia z wątku UI (This blog post ma dobrą pracę opisując ją i daje kilka innych dobre wskazówki), dokonałem prostej zmiany i nie udało się jeszcze odtworzyć błędu!
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.
}
Aby upewnić się, ja cię rozumiem poprawnie, w skrócie, jest to impas w 'SerialPort' pomiędzy' Read' a Wywołania "Zamknij"? – chezy525
musisz zmienić sposób wywoływania aktualizacji elementów interfejsu użytkownika w procedurze obsługi zdarzeń port_DataReceived, użyć BeginInvoke do aktualizacji zamiast Invoke lub zgodnie z opisem w rozwiązaniu użyć innego wątku do obsługi zdarzenia. – Afshin
Wygląda na to, że obsługa danych dla interfejsu w innym wątku rozwiązała problem. Dzięki! – chezy525