2011-09-08 21 views
7

Ocasionalmente algunas de mis pruebas de integración están fallando con el mensaje anterior. Estoy usando el siguiente código para preparar el puerto.SerialPort UnauthorizedAccessException

  for(int i = 0; i < 5; i++) 
      { 
       try 
       { 
        port.Open(); 
        if (port.IsOpen) 
         break; 
       } 
       catch (Exception e) 
       { 
        try 
        { 
         port.Close(); 
        } 
        catch (Exception) 
        {} 
        Thread.Sleep(300); 
       } 
      } 

Mi suposición es que debido a que no puede ser el hilo actual bloqueo del puerto (porque va a tratar de cerrarla), debe ser otro hilo o proceso que ha muerto sin limpiar adecuadamente (una de las otras pruebas - nada más tiene acceso a este puerto). ¿Hay alguna manera de restablecer el estado de SerialPort para que el nuevo subproceso/proceso pueda acceder a él nuevamente?

Gracias,

Richard

Respuesta

11

Este es un defecto en la clase SerialPort, utiliza un hilo de ayuda interna que esperar a que los acontecimientos en el puerto. El origen de los eventos DataReceived, PinChanged y ErrorReceived. El error está en la implementación del método Close(), no espera a que finalice este subproceso de ayuda. Eso lleva tiempo, la cantidad exacta de tiempo no es predecible y podría demorar varios segundos cuando la máquina está particularmente ocupada. El puerto físico no se cierra hasta que esto sucede, abriendo el puerto antes de que el hilo salga de las bombas con una excepción 'puerto ya en uso'. El que obtienes Dormir durante 300 mseg no es suficiente.

Esto no suele ser un problema, los puertos serie no son dispositivos compartibles. Cerrar un puerto serie y no salir de su programa es peligroso, otro proceso podría robar el puerto. También le doy esta excepción cuando intenta abrirlo de nuevo. La práctica habitual es abrir el puerto cuando se inicia la aplicación y no cerrarlo hasta que finalice.

+0

Gracias Hans: esto solo sucede en las pruebas cuando se inician diferentes procesos de prueba. –

2

que no puedo ver donde se cierra el puerto.

El problema para mí no está aquí (aunque se debe refactorizar un poco el código), pero, probablemente, a la que llama port.Open(); cuando el puerto está todavía abierta

De MSDN

Sólo una conexión abierta puede existir por objeto SerialPort.

(No puedo decir por qué porque no tengo suficiente información) Tenga también en cuenta que el método de cierre lleva tiempo cerrar realmente el puerto, de hecho, debe bloquear el hilo principal hasta que el puerto se estrecha (tal vez usando Thread.Join)

de MSDN

la mejor práctica para cualquier aplicación es esperar a que una cierta cantidad de tiempo después de llamar al método Close antes de intentar llamar al método abierto, como el puerto no se puede cerrar al instante.

para obtener más información

http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.open.aspx

+0

@Massimilano - gracias por su respuesta. El puerto se cierra en el bloque catch después de dormir durante 300 ms (cuando el abierto falla, se lanza una excepción). –

+0

Puedo ver eso, pero cierra el puerto solo si se lanza una excepción. si el puerto.Open() no arroja una excepción, el .Close() no se ejecutará –

+0

Disculpe si no estaba claro. La razón por la que el abierto está fallando es debido a la excepción de acceso no autorizado que se está lanzando (razón por la cual estaba intentando cerrar). –

4

Compruebo rutinariamente que el puerto está cerrado justo antes de crear una instancia de un puerto serie. Esto ayuda si deja de depurar código sin cerrar el puerto serie. También debe esperar 250 ms después de abrir o cerrar el puerto antes de continuar con su código.

try 
     { 
      if ((m_SerialPort != null)) 
      { 
       if (m_SerialPort.IsOpen) 
       { 
        m_SerialPort.Close(); 
       } 
      } 
      m_SerialPort = new SerialPort(portName, dataRate, parity, databits, stopBits.One); 
      m_SerialPort.Open(); 
      if (!m_SerialPort.IsOpen) 
      { 
       MessageBox.Show(string.Concat(portName, " failed to open")); 
      } 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show(ex.Message); 
     } 
0

GC.SuppressFinalize y GC.ReRegisterForFinalize deberían ser llamados pasar la instancia BaseStream propiedad SerialPort como parámetro y no sólo la instancia SerialPort.

Cuestiones relacionadas