2009-08-23 7 views
7

Buon pomeriggio a tutti!"L'handle sicuro è stato chiuso" con SerialPort e una discussione in C#

Ho questo wrapper con filettatura SerialPort che legge in una linea dalla porta seriale. Ecco il codice del mio thread.

protected void ReadData() 
{ 
    SerialPort serialPort = null; 
    try 
    { 
     serialPort = SetupSerialPort(_serialPortSettings); 
     serialPort.Open(); 

     string data; 
     while (serialPort.IsOpen) 
     { 
      try 
      { 

       data = serialPort.ReadLine(); 
       if (data.Length > 0) 
        ReceivedData(serialPort, new ReceivedDataEventArgs(data)); 

      } 
      catch (TimeoutException) 
      { 
       // No action 
      } 
     } 
    } 
    catch (ThreadAbortException) 
    { 
     if (serialPort != null) 
      serialPort.Close(); 
    } 
} 

quando chiamo myThread.Abort(); ottengo un'eccezione (con nessuna linea o il riferimento a codice) "maniglia di sicurezza è stato chiuso". Qualcuno può capire cosa sto facendo male? Grazie.

A proposito, ho uno Start() e uno Stop() che crea il thread e interrompe il thread, rispettosamente.

+0

Ho aggiunto qualche esempio di codice –

risposta

10

Sospetto che sia perché si utilizza Thread.Abort per terminare il thread, che in genere è disapprovato. Il comportamento del thread quando si abortisce non è prevedibile. Per questo motivo, poiché la porta seriale è un wrapper sul codice nativo, ci sono risorse native - rappresentate da SafeHandle in .NET - che vengono eliminate in modo imprevisto e quindi si ottiene l'eccezione.

È possibile pensare a ciò che accade con il tuo thread in questo modo:

  • si avvia il filo
  • si apre la porta seriale (che alloca le risorse autoctone e usa SafeHandle (s) a tenere a quelli risorse)
  • di iniziare a leggere dalla porta seriale
  • poi ad un certo punto (inaspettate alla vostra discussione) si chiama Thread.Abort su di esso
  • molto probabilmente il codice nel tuo thread è a tha t point tenta di accedere alla porta seriale (per leggere i dati)
  • il thread viene ucciso e l'handle della porta seriale viene distrutto in modo implicito
  • si ottiene un'eccezione generata dal codice all'interno della funzione ReadLine() della porta seriale perché la maniglia che aveva non è più valida

Si consiglia di utilizzare un metodo diverso per interrompere la discussione in modo da ottenere un'opportunità corretta per chiudere e smaltire la porta seriale.

Un modo corretto di chiudere la discussione potrebbe essere implementato usando un ManualResetEvent come questo:

protected ManualResetEvent threadStop = new ManualResetEvent(false); 

protected void ReadData() 
{ 
    SerialPort serialPort = null; 
    try 
    { 
     serialPort = SetupSerialPort(_serialPortSettings); 
     serialPort.Open(); 

     string data; 
     while (serialPort.IsOpen) 
     { 
      try 
      { 

       data = serialPort.ReadLine(); 
       if (data.Length > 0) 
        ReceivedData(serialPort, new ReceivedDataEventArgs(data)); 

      } 
      catch (TimeoutException) 
      { 
       // No action 
      } 

      // WaitOne(0) tests whether the event was set and returns TRUE 
      // if it was set and FALSE otherwise. 
      // The 0 tells the manual reset event to only check if it was set 
      // and return immediately, otherwise if the number is greater than 
      // 0 it will wait for that many milliseconds for the event to be set 
      // and only then return - effectively blocking your thread for that 
      // period of time 
      if (threadStop.WaitOne(0)) 
       break; 
     } 
    } 
    catch (Exception exc) 
    { 
     // you can do something here in case of an exception 
     // but a ThreadAbortedException should't be thrown any more if you 
     // stop using Thread.Abort and rely on the ManualResetEvent instead 
    } 
    finally 
    { 
     if (serialPort != null) 
      serialPort.Close(); 
    } 
} 

protected void Stop() 
{ 
    // Set the manual reset event to a "signaled" state --> will cause the 
    // WaitOne function to return TRUE 
    threadStop.Set(); 
} 

Naturalmente, quando si utilizza il metodo di eventi per fermare il filo bisogna fare attenzione ad includere un evento controllo dello stato in tutti i tuoi loop o attività da lungo tempo. Se non lo fai, il tuo thread potrebbe non rispondere alle tue impostazioni dell'evento - fino a quando non esce dal ciclo di lunga durata, o attività e ha la possibilità di "vedere" che l'evento è stato impostato.

+0

Quale sarebbe il modo corretto di chiudere il mio thread. I 'Stop()'/'Start()' sono usati per quando riconfigurare la porta. –

+0

Ci sono alcuni modi per farlo e ho dato un esempio usando ManualResetEvent che è un meccanismo piuttosto comune .. –

+0

Sweet. Grazie! –

0

Sono rientrato in una situazione simile in cui ho tentato di creare connessioni di porta seriale locali a un singolo metodo.

L'idea era di creare fino a quattro oggetti serialPort (per ciascuna porta seriale). Una volta che una delle porte tornava con buoni dati, sapevo a quale porta era collegato il mio dispositivo. Scarto tutti i miei oggetti "di prova" e creo una nuova connessione alla porta specifica.

Ogni volta attraverso il metodo creo/scarto gli oggetti serialPort. Ops. Accade così che se il GC non fosse passato prima che avessi chiamato il metodo, avrebbe tentato di creare una seconda connessione seriale che sostituisse la prima connessione e si sarebbero scontrati. Quello attiverebbe questo errore.

Soluzione: rendere globali tutti gli oggetti di connessione della porta seriale alla classe. Hack brutto: Sì, ma funziona

Problemi correlati