2009-08-11 13 views
9

Ho il codice seguente:Quanto è profondo il blocco?

  locker = new object(); 
     lock (locker) 
     { 
      for (int i = 0; i < 3; i++) 
       ver_store[i] = atomic_Poll(power);     
     } 

Stavo vagando, considerando la funzione all'interno della serratura accede alcune risorse globali, (un socket aperto tra di loro) se tutte le risorse globali all'interno dell'oggetto sono anche bloccati. (Sono consapevole che qualsiasi altra funzione che accede a queste stesse variabili deve implementare un blocco su di esse anche perché il meccanismo di blocco sia valido. Non ho ancora ottenuto il blocco per chiuderle :))

risposta

11

dichiarazione La serratura non "Blocca codice" o qualsiasi risorsa che va tra le parentesi graffe pre se.

Trovo che sia meglio comprendere il blocco da una prospettiva di thread (dopo tutto, gli scenari di threading sono quando è necessario considerare il blocco).

Dato il suo codice di esempio

10 locker = new object(); 
11 lock (locker) 
12 { 
    ... 
15 } 

Quando il filo X raggiunge la linea 10 viene creato un nuovo oggetto e alla linea 11, un blocco viene acquisito sull'oggetto. Thread X continua a eseguire qualsiasi codice all'interno del blocco.

Ora, mentre filettatura X è al centro del nostro blocco, filo Y raggiunge la linea 10. Lo ed ecco, viene creato un nuovo oggetto, e poiché è creato da filo Y serratura è attualmente acquisito su questo oggetto. Quindi, quando il thread Y raggiunge 11, acquisirà un blocco sull'oggetto e continuerà a eseguire il blocco contemporaneamente alla thread X.

Questa è la situazione che il blocco doveva impedire. Quindi che si fa? Make locker a oggetto condiviso.

01 static object locker = new object(); 

    ... 

11 lock (locker) 
12 { 
    ... 
15 } 

Ora, quando il filo X raggiunge la linea 11 sarà acquisire il blocco e inizia l'esecuzione del blocco. Quando il thread Y raggiunge la riga 11, proverà ad acquisire un blocco sullo stesso oggetto del thread X. Poiché questo oggetto è già bloccato, il thread Y attenderà fino al rilascio del blocco. Impedendo così l'esecuzione concorrente del blocco di codice, proteggendo così tutte le risorse utilizzate da quel codice per l'accesso simultaneo.

Nota: se altre parti del sistema devono essere serializzate attorno alle stesse risorse, devono cercare di bloccare lo stesso oggetto di blocco condiviso.

+0

Una spiegazione ancora migliore per un principiante. Grazie mille oh –

+0

Sei così totalmente benvenuto :) –

3

È molto semplice- il blocco blocca il codice all'interno dell'istruzione di blocco. Se stai utilizzando queste risorse altrove nel tuo codice, non saranno coperte da quel blocco.

Alcune classi dispongono di meccanismi su di esse in modo da poter bloccare in più posizioni, un esempio di questo è lo Hashtable's Syncroot property. L'utilità di questo è questionable though. A nice discussion about it is on SO.

La soluzione migliore è incapsulare questa logica nella propria classe, con un meccanismo di blocco interno e assicurarsi che l'app utilizzi solo tale classe.

1

Il blocco non si riferisce ad alcun oggetto - si riferisce solo a un pezzo di codice. Quindi, se hai 2 diverse funzioni che funzionano con il socket globale, devi controllarle entrambe, per il tuo esempio deve essere lo stesso oggetto 'locker', quindi renderlo visibile per entrambi i codici.

4

Il blocco interessa solo il codice nel corpo della dichiarazione di blocco. Gli oggetti passati come parametro agiscono come un identificatore univoco, non sono influenzati internamente in alcun modo.

1

Risposta breve: No

Locking è un concetto logico, non un fisico quello in cui la lingua/cpu deduce la portata di una serratura e limita l'accesso a tutti gli elementi che rientrano nel campo. È tuo compito imporre l'utilizzo del blocco, quindi se devi acquisire il blocco X per utilizzare la risorsa Y, devi assicurarti di farlo sempre.

3

Come indicato da tutti qui ...

  • blocco è un concetto logico
  • chiavistello blocca solo quello che c'è nel blocco di codice tra parentesi graffe.

Ma per darvi una breve panoramica:

blocco non è altro che un sostituto per Monitor.Enter e Monitor.Exit. Proprio questo, con il blocco Monitor.Exit viene inserito in un blocco finale.

Allora, che cosa siete EFFETTIVAMENTE blocco è (nel codice) è l'oggetto armadietto. Quindi, ovunque nel tuo codice se usi questo locker per il blocco, quel blocco di codice sarà bloccato.

La mia ipotesi è questo è come il blocco funziona: (guru, per favore correggetemi se sbaglio)

if(locker.SyncBlockIndex <0)>              
{                     
//obtain an index to free synch cache block          
//assign the index obtained in previous step to obj.SyncBlockIndex    
}                     
syncblock = syncblockCache[locker.SyncBlockIndex]         
if(!syncblock is owned by the calling thread)          
{                     
//susped the calling thread              
}    

Vedi se questo link ti aiuta a capire la serratura (avevo scritto questo post qualche tempo fa)

http://dotenetscribbles.blogspot.com/2008/10/calling-monitorenter-recursively.html

2

un blocco è solo una pedina. Fintanto che alcuni thread sono in possesso di un lock specifico, ad altri thread non sarà permesso di ottenere quel lock e quindi sarà impedito di eseguire il codice che è sincronizzato usando il lock in questione.

Si consiglia di controllare le risposte a questa domanda così: Does lock(){} lock a resource, or does it lock a piece of code?