Blocchi rientranti in C #


119

Il codice seguente determinerà un deadlock utilizzando C # su .NET?

 class MyClass
 {
    private object lockObj = new object();

    public void Foo()
    {
        lock(lockObj)
        { 
             Bar();
        }
    }

    public void Bar()
    {
        lock(lockObj)
        { 
          // Do something 
        }
    }       
 }

6
Potremmo prendere in considerazione la possibilità di modificare il titolo di questa domanda, magari in qualcosa di simile alla chiusura recente. Perché i blocchi annidati non causano un deadlock? Allo stato attuale, il titolo sembra quasi progettato per impedire alle persone di scoprirlo.
Jeff Sternal,

12
In realtà l'ho trovato in base alla parola di ricerca "rientrante" e ha risposto alla mia domanda. Se è una domanda duplice, è un problema diverso ...
emfurry

Sono d'accordo con @JeffSternal commento questa domanda presuppone che la persona che cerca la domanda abbia già familiarità con le serrature "Rientrante". Un'altra domanda di duplicazione che penso avesse un buon titolo per questo: stackoverflow.com/questions/3687505/…
Luis Perez

Risposte:


148

No, non fintanto che stai bloccando lo stesso oggetto. Il codice ricorsivo ha già effettivamente il blocco e quindi può continuare senza ostacoli.

lock(object) {...}è una scorciatoia per usare la classe Monitor . Come sottolinea Marc , Monitorconsente il rientro , quindi i tentativi ripetuti di bloccare un oggetto su cui il thread corrente ha già un blocco funzioneranno perfettamente.

Se inizi a bloccare oggetti diversi , è allora che devi stare attento. Prestare particolare attenzione a:

  • Acquisisci sempre blocchi su un determinato numero di oggetti nella stessa sequenza.
  • Rilascia sempre i blocchi nella sequenza inversa a come li acquisisci.

Se si interrompe una di queste regole si sta praticamente la garanzia di ricevere le questioni di stallo a un certo punto .

Ecco una buona pagina web che descrive la sincronizzazione dei thread in .NET: http://dotnetdebug.net/2005/07/20/monitor-class-avoiding-deadlocks/

Inoltre, blocca il minor numero di oggetti alla volta possibile. Considera l' idea di applicare ciocche a grana grossa, ove possibile. L'idea è che se puoi scrivere il tuo codice in modo tale che ci sia un oggetto grafico e puoi acquisire blocchi sulla radice di quell'oggetto grafico, allora fallo. Ciò significa che hai un blocco su quell'oggetto root e quindi non devi preoccuparti troppo della sequenza in cui acquisisci / rilascia i blocchi.

(Un'ulteriore nota, il tuo esempio non è tecnicamente ricorsivo. Perché sia ​​ricorsivo, Bar()dovrebbe chiamare se stesso, tipicamente come parte di un'iterazione.)


1
Soprattutto in sequenze diverse.
Marc Gravell

6
Re ricorsione; infatti; a beneficio di Guy, il termine è rientrante
Marc Gravell

Grazie per il chiarimento sulla terminologia - Ho modificato e corretto la domanda.
Guy

Questa domanda sembra attirare un po 'di attenzione, quindi ho aggiornato la mia risposta con un paio di altre note che ho escogitato da quando l'ho scritta per la prima volta.
Neil Barnwell

In realtà, non credo che l'ordine in cui rilasci i lucchetti sia importante. L'ordine in cui li scegli fa sicuramente, ma fintanto che il rilascio del blocco non è subordinato a nulla (puoi rilasciarlo in qualsiasi momento), dovresti stare bene fintanto che rilasci tutti i blocchi che hai acquisito.
bobroxsox

20

Bene, Monitorconsente il rientro, quindi non puoi bloccarti ... quindi no: non dovrebbe funzionare


7

Se un thread ha già un blocco, non si bloccherà da solo. Il framework .Net lo garantisce. Devi solo assicurarti che due thread non tentino di acquisire gli stessi due blocchi fuori sequenza da qualsiasi percorso di codice.

Lo stesso thread può acquisire lo stesso blocco più volte, ma è necessario assicurarsi di rilasciare il blocco lo stesso numero di volte in cui lo si acquisisce. Ovviamente, finché utilizzi la parola chiave "lock" per farlo, avviene automaticamente.


Nota che questo è vero per i monitor, ma non necessariamente per altri tipi di blocco.
Jon Skeet

(Non voglio implicare che non lo sapessi, ovviamente - solo che è una distinzione importante :)
Jon Skeet,

È un buon punto. In realtà stavo per cambiare "blocco" in "monitor" per tutto il tempo, ma poi mi sono distratto. E pigro. E il comportamento è vero anche per gli oggetti mutex kernal di Windows, quindi ho pensato, abbastanza vicino!
Jeffrey L Whitledge,

5

No, questo codice non avrà dead lock. Se vuoi davvero creare deadlock, il più semplice richiede almeno 2 risorse. Considera lo scenario del cane e delle ossa. 1. Un cane ha il pieno controllo di 1 osso, quindi qualsiasi altro cane deve aspettare. 2. Sono necessari almeno 2 cani con 2 ossa per creare un punto morto quando si bloccano rispettivamente le loro ossa e cercano anche altre ossa.

.. così via e così via n cani e m ossa e causare situazioni di stallo più sofisticate.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.