2012-04-11 24 views
7

Ho scritto codice semplice (allegato) e non capisco perché il blocco su qualche blocco non blocchi l'oscilloscopio.Perché il blocco di questo codice non funziona?

Il codice:

object locker = new object(); 
    private void foo(int i) 
    { 
     Console.WriteLine(string.Format("i is {0}", i)); 
     lock(locker) 
     { 
      while(true) 
      { 
       Console.WriteLine(string.Format("i in while loop is {0}", i)) ; 
       foo(++i); 
      } 
     } 
    } 

mi aspetto che la chiamata per il metodo foo nel ciclo while sarà in attesa fino a quando l'armadio sarà di rilascio (portata armadietto) - ma tutte le chiamate del foo con arg di ++ posso entrare nel blocco degli armadietti.

+0

Penso che sia lo stesso thread quindi non dovrebbe bloccarsi (forse qualcuno lo sa in modo più dettagliato) – V4Vendetta

+0

ho sicuramente imparato qualcosa di nuovo su questo, +1 –

+11

Se sei già in bagno, e la porta è già bloccato, e metti un * secondo * lucchetto sulla porta, * sei già in bagno. * –

risposta

12

Il blocco utilizzato qui è rientrante. Impedirà ad un altro thread di entrare nel monitor, ma il thread che blocca il blocco non verrà bloccato.

+0

non avevo idea di come funzionasse - sei al 100% su questo giusto? –

+2

@Gabriel Questo è esattamente giusto; l'istruzione 'lock' in C# è rientrante. Non puoi bloccare "te stesso". – dlev

+0

non è quello che succede in C/C++, a meno che la mia memoria non venga ripresa (e forse lo è) - semplicemente sorprendente che non ho mai realizzato una tale differenza –

7

La parola chiave di blocco è solo zucchero sintattico nei metodi Monitor.Enter e Monitor.Exit. Come si vede nella documentation per Monitor:

E 'legale per lo stesso thread di invocare inserire più di una volta senza bloccare;

Chiamare lock(object) dallo stesso thread più di una volta non ha alcun effetto se non quello di aumentare il conteggio dei blocchi.

+0

c'è un altro tipo di blocco che si comporta come il manifesto previsto Monitorare/bloccare per comportarsi? –

+1

@Gabriel, è possibile utilizzare 'AutoResetEvent' per questo. – svick

+1

@Gabriel 'SpinLock' non è rientrante, IOW,' SpinLonk.Enter' fallirà se chiamato sullo stesso thread che già detiene il lock; i due non sono esattamente gli stessi, ma avrebbero funzionato come sembrava aspettarsi l'OP. –

1

Quando si effettua una chiamata ricorsiva qui sul thread dire t1, non si sta eseguendo una filettatura separata. La chiamata ricorsiva viene effettuata sullo stesso thread t1.

Poiché t1 è già in possesso del blocco, non è necessario attendere il blocco.

Problemi correlati