2012-03-08 21 views
20

Questo è da MSDN: La parola chiave di bloccaggio assicura che un thread non entra una sezione critica di codice, mentre un altro thread è in la sezione critica.Confusione circa l'istruzione lock in C#

una sezione critica deve essere uguale a la sezione critica?

O significa: La parola serratura assicura che un filo non entri qualsiasi sezione critica sorvegliata da un oggetto di codice mentre un altro thread è in qualsiasi sezione critica protetta dallo stesso oggetto. ?

class Program 
{ 
    static void Main(string[] args) 
    { 
     TestDifferentCriticalSections(); 

     Console.ReadLine(); 
    } 

    private static void TestDifferentCriticalSections() 
    { 
     Test lo = new Test(); 

     Thread t1 = new Thread(() => 
     { 
      lo.MethodA(); 
     }); 
     t1.Start(); 

     Thread t2 = new Thread(() => 
     { 
      lo.MethodB(); 
     }); 
     t2.Start(); 
    } 
} 

public class Test 
{ 
    private object obj = new object(); 

    public Test() 
    { } 

    public void MethodA() 
    { 
     lock (obj) 
     { 
      for (int i = 0; i < 5; i++) 
      { 
       Thread.Sleep(500); 
       Console.WriteLine("A"); 
      } 
     } 
    } 

    public void MethodB() 
    { 
     lock (obj) 
     { 
      for (int i = 0; i < 5; i++) 
      { 
       Thread.Sleep(500); 
       Console.WriteLine("B"); 
      } 
     } 
    } 
} 
+3

È più su Grammar che C#, "il" è un valore definitivo mentre "a" è indefinito e potrebbe riferirsi a qualsiasi sezione di codice. http://www.englishclub.com/grammar/adjectives-determiners-the-a-an.htm – Lloyd

risposta

63

La domanda è formulata in modo confuso e le risposte finora non sono particolarmente chiare. Lasciatemi riformulare la domanda in diverse domande:

(1) L'istruzione di blocco garantisce che non ci sia più di un thread nel corpo dell'istruzione di blocco in qualsiasi momento?

No. Ad esempio:

static readonly object lock1 = new object(); 
static readonly object lock2 = new object(); 
static int counter = 0; 
static object M() 
{ 
    int c = Interlocked.Increment(ref counter); 
    return c % 2 == 0 ? lock1 : lock2; 
} 

... 
lock(M()) { Critical(); } 

È possibile che due fili di essere entrambi nel corpo della istruzione lock allo stesso tempo, in quanto i blocchi istruzione lock su due oggetti diversi. Thread Alpha può chiamare M() e ottenere lock1, quindi thread Beta può chiamare M() e ottenere lock2.

(2) Partendo dal presupposto che la mia dichiarazione di blocco blocca sempre sullo stesso oggetto, non una dichiarazione di blocco in modo che non più di un filo "attiva" è nel corpo della serratura in qualsiasi momento?

Sì. Se si dispone di:

static readonly object lock1 = new object(); 
... 
lock(lock1) { Critical(); } 

quindi infilare Alpha può prendere la serratura, e filo Beta blocco fino a quando il blocco è disponibile prima di entrare nel corpo della serratura.

(3) Supponendo di avere due istruzioni di blocco e entrambe le istruzioni di blocco bloccano lo stesso oggetto ogni volta, un'istruzione di blocco assicura che non ci sia più di un thread "attivo" nel corpo di entrambi i blocchi in qualsiasi momento?

Sì.Se si dispone di:

static readonly object lock1 = new object(); 
... 
static void X() 
{ 
    lock(lock1) { CriticalX(); } 
} 
static void Y() 
{ 
    lock(lock1) { CriticalY(); } 
} 

quindi se filo Alpha è in X e prende la serratura, e filo Beta è in Y, quindi infilare Beta blocco finché la serratura è disponibile prima di entrare nel corpo della serratura.

(4) Perché stai mettendo "attivo" in "virgolette"?

per richiamare l'attenzione sul fatto che è possibile per un aspettando filo di essere nel corpo della serratura. È possibile utilizzare il metodo Monitor.Wait per "mettere in pausa" un thread che si trova in un corpo del blocco e consentire a un thread bloccato di diventare attivo e immettere il corpo del blocco (o un corpo di blocco diverso che blocca lo stesso oggetto). Il thread in attesa rimarrà nel suo stato di "attesa" fino a quando non pulsa. A un certo punto, dopo essere pulsato, si ricongiunge alla coda "pronta" e ai blocchi finché non ci sono thread "attivi" nel blocco. Quindi riprende dal punto in cui era stato interrotto.

+3

Come sempre, le vostre risposte superano di gran lunga le mie in modo accurato e accurato. E per questo, ti farò una doccia di voti positivi. –

+1

E ancora una volta, mi sento di leggere una delle tue risposte. Grazie Eric. – MoonKnight

+1

+1 per mettere * attivo * tra virgolette spaventose. ;-) È molto necessario qui. – Nawaz

5

Si mette un lucchetto su un oggetto. Se un altro thread tenta di accedere a una sezione critica contrassegnata da quell'oggetto nello stesso momento, bloccherà fino a quando il blocco non verrà rimosso/completato.

Esempio:

public static object DatabaseLck= new object(); 

lock (DatabaseLck) { 
     results = db.Query<T>(query).ToList(); 
    } 

Oppure

lock (DatabaseLck) { 
     results = db.Query<T>(string.Format(query, args)).ToList(); 
    } 

Nessuno di questi blocchi di codice può essere eseguito contemporaneamente perché utilizzano lo stesso oggetto di blocco. Se hai utilizzato un oggetto di blocco diverso per ciascuno, potrebbero essere eseguiti contemporaneamente.

+0

"Se un altro thread tenta di accedere a quell'oggetto nello stesso momento, bloccherà" - Intendevi: "Se un altro thread tenta di accedere a una sezione critica contrassegnata da quell'oggetto allo stesso tempo, bloccherà "? – CuiPengFei

+0

Sì. Grazie. Ho aggiornato la mia risposta. –

0

No, significa che un altro thread non entrerà nella sezione critica protetta da questa istruzione di blocco.

la sezione critica è definito solo dal programmatore, e in questo caso, si potrebbe sostituirlo con: sezione protetta da una serratura

Così traduzione: Il lock parola chiave assicura che un thread non immette un sezione del codice protetta da un lock mentre un altro thread è in questa sezione di codice (protetto da un lock)

+2

Non dovrebbe significare che è una sezione protetta dallo stesso oggetto di blocco? – erict

+0

No, perché l'oggetto che si utilizza nel blocco viene utilizzato solo per garantire il blocco. – squelos

+1

@squelos: qualsiasi sezione che blocca lo stesso oggetto è bloccata da un blocco su quell'oggetto. –

2

È la stessa sezione critica.

lock (synclock) 
{ 
    // the critical section protected by the lock statement 
    // Only one thread can access this at any one time 
} 

Vedi lock Statement su MSDN:

La parola serratura contrassegna un blocco di istruzioni come una sezione critica ottenendo il bloccaggio mutua esclusione per un determinato oggetto, esecuzione di un'istruzione, e poi rilasciando il blocco .


o significa: La parola serratura assicura che un thread non entri qualsiasi sezione critica del codice mentre un altro thread è in ogni sezione critica. ?

No. Non significa questo. Significa che la sezione critica è protetta da quel blocco e da quel blocco.


Update, codice di esempio seguente:

Se si utilizza un singolo oggetto per agganciare, si blocca tutti sezioni critiche, causando altri thread di bloccare fino al rilascio. Nell'esempio di codice, una volta inserito il blocco in MethodA, tutti gli altri thread che raggiungono tale blocco e il blocco su MethodB verranno bloccati fino al rilascio del blocco (ciò accade perché si sta bloccando lo stesso oggetto in entrambi i metodi).

+0

downvote: fare riferimento al codice che ho aggiunto al post – CuiPengFei

+0

@CuiPengFei - Risposta aggiornata. – Oded

0

La sezione critica di cui si parla è la sezione protetta dalle istruzioni di blocco.

Qualsiasi sezione critica che si blocca sullo stesso oggetto verrà bloccata dall'accesso.

È inoltre importante che l'oggetto di blocco sia statico, poiché i blocchi devono bloccarsi (o tentare di bloccarsi) sulla stessa istanza dell'oggetto di blocco.

+5

** Non utilizzare il blocco a doppio controllo a meno che non si sia verificato un problema di prestazioni con il blocco corretto. ** Esistono circa un milione di modi per ottenere il blocco del doppio controllo errato e un solo modo per farlo correttamente; è un modello * follemente pericoloso * se usato con noncuranza. Se pensi che dovresti usare il blocco con doppia verifica, * ripensa *. Probabilmente è possibile risolvere il problema con (1) blocco regolare, (2) scambio interbloccato, (3) la classe Lazy , (4) sfruttando la semantica di blocco di inizializzatore della classe statica. –

+0

@EricLippert: ho sempre avuto l'impressione che il blocco a doppia verifica fosse una necessità. Grazie per il chiarimento. Ho rimosso quel commento dalla mia risposta, ma penso che il resto resti ancora in discussione. –

+0

No, il blocco a doppio controllo è una tecnica * a basso blocco per l'ottimizzazione delle prestazioni *, e come qualsiasi tecnica di blocco basso, è pazzesca pericolosa. –

1

Non significa qualsiasi, sebbene sia possibile proteggere 2 blocchi di codice dall'essere immessi da più di un thread contemporaneamente bloccandoli entrambi con lo stesso oggetto. Questo è un paradigma comune: potresti voler bloccare la tua raccolta per cancellare e scrivere.