2010-05-20 3 views
8

Ho una situazione in cui un blocco di codice deve essere eseguito solo se due oggetti locker sono liberi.Come utilizzare più variabili per un blocco Ambito in C#

Speravo ci sarebbe qualcosa di simile:

lock(a,b) 
{ 
    // this scope is in critical region 
} 

Tuttavia, sembra che ci sia niente di simile. Quindi vuol dire che l'unico modo per farlo è:

lock(a) 
{ 
    lock(b) 
    { 
     // this scope is in critical region 
    } 
} 

Funzionerà anche come previsto? Sebbene il codice compili, ma non sono sicuro che sarebbe in grado di raggiungere ciò che mi aspetto.

+0

Non potrebbe causare problemi di blocco? diciamo che un oggetto blocca un, e un altro blocca b, ora avresti un deadlock in cui l'oggetto1 blocca un blocco di attesa b e object2 b in attesa di un. Non sono così familiare con le serrature, ma questo mi sembra brutto. – Tester101

+2

Ecco perché l'ordine di blocco è importante, come tutte le risposte finora menzionate. A volte è necessario disporre di più blocchi e, in questi casi, uno dei modelli standard da utilizzare consiste nell'applicare (tramite convenzione almeno) un ordinamento sui blocchi. Ad esempio, dovresti dire ogni volta che vuoi ottenere il blocco b * devi * prima ottenere il blocco su a.Provoca più contesa, ma previene i deadlock. È sempre meglio evitare questo genere di cose quando possibile, ma a volte è necessario. – Herms

+0

@ Tester101: Sì, sono consapevole che, se non gestito correttamente, causerà deadlock. –

risposta

5

Mi aspetterei che, anche se ci sarebbe un caso in cui potrebbe potenzialmente causare una condizione di deadlock.

Normalmente, il codice tenterà di bloccare a e quindi procedere al blocco b se riuscito. Ciò significa che eseguirà il codice solo se potrebbe bloccare sia a sia b. Che è quello che vuoi

Tuttavia, se qualche altro codice ha già un blocco su b, questo codice non farà ciò che ci si aspetta. Dovresti anche assicurarti che ovunque tu abbia bisogno di bloccare sia a che b tu tenti di ottenere i blocchi nello stesso ordine. Se si ottiene b prima e quindi a si causerebbe un deadlock.

+0

In realtà non fallirà se qualcos'altro ha un blocco su b - aspetterà che venga rilasciato. – TomTom

+1

@TomTom: se l'altro thread tenta di accedere a uno dei blocchi, non avremo alcun problema, ma se tenta di bloccare sia a che b in ordine inverso, ci sono buone possibilità di deadlock. @ChrisF: Sono necessarie parentesi graffe esterne nella modifica oppure l'hai fatto solo per rendere il codice più pulito? –

+0

@Gunner - solo un tentativo di rendere il codice più pulito e chiarire l'ambito della serratura. Spero che sia OK. – ChrisF

11

Richiedere il blocco su entrambi dovrebbe funzionare correttamente. lock(a) bloccherà fino a a è gratuito. Una volta che hai quel blocco, lock(b) bloccherà finché non avrai b. Dopo che hai entrambi.

Una cosa che devi fare molta attenzione qui è l'ordine. Se hai intenzione di fare questo assicurati di ottenere sempre prima di ottenere il blocco a prima di ottenere il blocco b. Altrimenti potresti trovarti facilmente in una situazione di stallo.

15
lock(a) lock(b) { // this scope is in critical region } 

Questo potrebbe bloccherebbe finché il filo può acquisire il blocco per a. Quindi, con quel blocco acquisito, si bloccherebbe fino a che il thread non acquisisse il blocco per b. Quindi funziona come previsto.

Tuttavia, bisogna stare attenti a non fare questo da qualche altra parte:

lock(b) lock(a) { // this scope is in critical region } 

Questo potrebbe portare ad una situazione di stallo in cui filo 1 ha acquisito il blocco per a ed è in attesa di acquisire il blocco per b e il thread 2 ha acquisito il blocco per b ed è in attesa di acquisire il blocco per a.