2010-08-25 8 views
10

Si consideri la seguente funzione che implementa l'accesso non bloccante solo a un thread.Domanda sull'utilizzo di Monitor.TryEnter e oggetto di blocco

public bool TryCancelGroup() 
{ 
    if (Monitor.TryEnter(_locked)) 
    { 
     if (_locked == false) 
     { 
      _locked = true; 

      try 
      { 
       // do something 
      } 
      catch (Exception ex) 
      { 
       _locked = false; 
      } 
      finally 
      { 
       Monitor.Exit(_locked); 
      } 
     } 
     return _locked; 
    } 
    else 
    { 
     return false; 
    } 
} 

Ed ecco come viene definita la variabile _locked.

bool _locked = false; 

Ora, quando il programma raggiunge Monitor.Exit(_locked); viene generata System.Threading.SynchronizationLockException detto che _locked variabile non erano sincronizzati prima.

E tutto è stato lavorare prima, quando _locked variabile è stata definita come oggetto

object _locked = new object(); 

Quando ho cambiato in bool al fine di utilizzarlo come flag booleano ho cominciato a ricevere questa eccezione.

+1

JaredPar ha fornito la risposta per il vostro problema. Ma la tua logica sembra essere sbagliata: se entri nel monitor con _locked = true, non uscirai mai dal monitor. – VinayC

+0

Oh certamente sì, grazie VinayC –

+0

Inoltre penso che di solito hai un oggetto statico come blocco. – Chris

risposta

20

Il motivo è che i metodi Monitor prendono tutti un parametro System.Object. Quando si passa in un bool è necessaria una casella per convertire in Object. L'operazione di casella produce un nuovo valore System.Object per ciascuna chiamata. Quindi i metodi TryEnter e Exit vedono oggetti e risultati diversi nell'eccezione.

Quando _locked è stato immesso in Object non è stato necessario alcun box. Quindi i metodi TryEnter e Exit vedono lo stesso oggetto e possono funzionare correttamente.

Pochi altri commenti circa il codice

  • TryEnter deve essere accoppiato con l'uscita in tutti i casi e per amor sanità mentale della chiamata uscita dovrebbe essere in un blocco finally. In caso contrario, si inviterà uno scenario di deadlock
  • La variabile _locked è impostata su false solo in presenza di un'eccezione. Se l'esecuzione non produce un'eccezione, rimarrà true e nessun thread verrà mai più inserito nel blocco if.
+0

O sì, sicuro. Ma il tipo di bool non è derivato da System.Object? Quindi è derivato da Object, ma ciononostante quando una conversione ad Object viene soddisfatta da qualche parte viene utilizzata un'operazione di boxing? Questa affermazione è corretta? –

+3

@Captain, quando un tipo di valore di qualsiasi tipo, 'bool' incluso, viene utilizzato in una posizione digitata su' System.Object' o un'interfaccia verrà eseguita un'operazione di boxing. – JaredPar

4

L'impostazione del timeout su un montior su 0 può aiutare a implementare il comportamento desiderato. Utilizzare un oggetto dichiarato globalmente contro cui bloccare.

static object mylock = new object(); 

....

if (Monitor.TryEnter(mylock, 0)) 
{ 
    try 
    { 
      // Do work 
    } 
    finally 
    { 
     Monitor.Exit(mylock); 
    } 
} 
+2

Monitor.TryEnter (mylock, 0) è lo stesso di Monitor.TryEnter (mylock) per quanto posso vedere in Reflector. – Chris

+0

Non dalla mia esperienza. Ho aggiunto il ", 0" al mio e ha risolto il problema che stavo avendo. –

+0

@Andrew 'oggetto statico var mylock' non è una dichiarazione di variabile valida. – tchelidze