2012-03-30 1 views
16

Vor kurzem habe ich diesen Code in einer Webseite zu sehen ist, und meine Frage ist folgende:Eine einzelne Bool-Variable beim Multithreading sperren?

 private bool mbTestFinished = false; 

     private bool IsFinished() 
     { 
      lock(mLock) 
      { 
       return mbTestFinished; 
      } 
     } 

     internal void SetFinished() 
     { 
      lock(mLock) 
      { 
       mbTestFinished = true; 
      } 
     } 

In einer Multi-Thread-Umgebung ist wirklich notwendig, den Zugang zum mbTestFinished zu sperren?

+6

Es ist der am besten beweisbare Mechanismus, um sicherzustellen, dass es kein CPU-Cache-Read (was nicht gut zwischen Threads funktionieren würde) - "volatile" würde auch funktionieren, aber aus Gründen, die zu komplex sind (das ist nicht die * Absicht * von 'volatile', aber eher: ein Nebeneffekt) –

+4

@MarcGravell Ich habe immer gedacht, dass _was_ die Absicht von' volatile' war; jede Chance, dass Sie einen guten Link fallen lassen, der erklärt, was ist? –

+1

@romkyns: Diese [Antwort] (http://stackoverflow.com/a/4103879/158779) bietet einige Einblicke. –

Antwort

9

Ja, es wird benötigt. Die .Net-Umgebung verwendet einige Optimierungen, und manchmal werden Daten, wenn auf einen Speicherort häufig zugegriffen wird, in CPU-Register verschoben. Wenn in diesem Fall mbTestFinished in einem CPU-Register ist, kann ein Thread, der es liest, einen falschen Wert erhalten. Die Verwendung des flüchtigen Schlüssels stellt somit sicher, dass alle Zugriffe auf diese Variable am Speicherort und nicht an den Registern erfolgen. Auf der anderen Seite habe ich keine Ahnung von der Häufigkeit dieses Vorkommens. Dies kann bei einer sehr niedrigen Frequenz auftreten.

9

Meiner Meinung nach, nein, das Schloss hier überflüssig ist, aus zwei Gründen:

  1. Booleschen Variablen Zuordnung zu reißen wie long zum Beispiel nicht dazu führen kann, ist daher Verriegelung nicht erforderlich.
  2. Um das Sichtbarkeitsproblem volatile zu lösen ist genug. Es ist wahr, dass die lock einen impliziten Zaun einführt, aber da die lock nicht für Atomizität erforderlich ist, ist volatile genug.
+0

Dies gilt, wenn angenommen wird, dass der gezeigte Code das * einzige * Ding ist, das die Sperre verwendet. Wenn es andere Orte gibt, an denen "mLock" verwendet wird, könnte die Umwandlung in "volatil" die Dinge zerstören. –

+0

@romkyns: Ja, ich nehme an, es ist ein in sich geschlossenes Szenario. – Tudor

4

Wenn mlock ist NUR für die Variable mbTestFinished, dann ist es ein bisschen zuviel des Guten. Stattdessen können Sie volatile oder Interlocked verwenden, da beide User-Mode-Konstrukte für Thread-Synchronisierung sind. sperren (oder -Monitor) ist ein Hybrid Konstrukt, in dem Sinne, dass es auch vom/zum Kernel-Mode wann immer möglich im Transit zu vermeiden optimiert ist. Das Buch "CLR via C#" diskutiert diese Konzepte eingehend.