2012-01-12 37 views
5

Tengo un programa de winform que hace un IO asincrónico en un SerialPort. Sin embargo, periódicamente encuentro un problema con el congelamiento del programa en la llamada SerialPort.Close(), aparentemente al azar.C# Winform freezing en SerialPort.Close

Creo que es un problema de seguridad de subprocesos, pero no estoy seguro de cómo solucionarlo si lo es. Traté de agregar/eliminar el controlador asincrónico DataReceived con las funciones de apertura/cierre del puerto y descartar los búferes de entrada y salida en el puerto, pero parece que no hace nada. Creo que el código importante SerialPort es el siguiente:

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. 
    } 
    } 
} 

ACTUALIZACIÓN

Gracias a @ respuesta de Afrin señalando la condición de punto muerto con el hilo de interfaz de usuario (This blog post hace un buen trabajo de describir, y da varios otros buenos consejos), hice un cambio simple y todavía no he podido reproducir el error.

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. 
} 

Respuesta

13

La razón sería colgar cuando se cierra es porque en el controlador de eventos de su objeto SerialPort

Está sincronizando una llamada con el hilo principal (normalmente llamando a invocar). El método de cierre de SerialPort espera a que su subproceso EventLoopRunner desencadene los eventos DataReceived/Error/PinChanged. pero dado que su propio código en el evento también está esperando la respuesta del hilo principal, se encontrará con una situación de bloqueo.

solución: utilizar BeginInvoke en lugar de invocar: https://connect.microsoft.com/VisualStudio/feedback/details/202137/serialport-close-hangs-the-application

referencia: http://stackoverflow.com/a/3176959/146622

+0

Para asegurarse de que he entendido bien, en resumen, hay un estancamiento en el '' SerialPort' entre el Read' y la 'Cerrar' llamadas? – chezy525

+0

tiene que cambiar la forma en que invoca las actualizaciones del elemento de la interfaz de usuario en el controlador de eventos port_DataReceived, use BeginInvoke para actualizar en lugar de Invoke, o como se describe en la solución, use otro hilo para manejar el evento. – Afshin

+0

El manejo de los datos para la interfaz de usuario en un hilo diferente parece haber resuelto el problema. ¡Gracias! – chezy525