Joe Albahari在C#中解釋了volatile
的一篇很好的文章:Threading in C#: PART 4: ADVANCED THREADING。易失性讀/寫和指令重新排序
考慮指令重新排序喬使用這個例子:
public class IfYouThinkYouUnderstandVolatile
{
private volatile int x, y;
private void Test1() // Executed on one thread
{
this.x = 1; // Volatile write (release-fence)
int a = this.y; // Volatile read (acquire-fence)
}
private void Test2() // Executed on another thread
{
this.y = 1; // Volatile write (release-fence)
int b = this.x; // Volatile read (acquire-fence)
}
}
基本上他的意思是,a
和b
都可以用包含0
時所述方法對不同的線程並行運行結束。
督察優化或處理器可能重新排序的說明如下:
public class IfYouThinkYouUnderstandVolatileReordered
{
private volatile int x, y;
private void Test1() // Executed on one thread
{
int tempY = this.y; // Volatile read (reordered)
this.x = 1; // Volatile write
int a = tempY; // Use the already read value
}
private void Test2() // Executed on another thread
{
int tempX = this.x; // Volatile read (reordered)
this.y = 1; // Volatile write (release-fence)
int b = tempX; // Use the already read value
}
}
的,爲什麼這會雖然我們使用volatile
發生的原因是,讀指令下一個寫指令可移動在之前寫入指令。
到目前爲止,我明白這裏發生了什麼。
我的問題是:可以通過堆棧幀重新排序嗎?我的意思是在一個易失性讀指令發生在另一個方法(或屬性訪問器)之後,可以將一條易失性寫指令移走嗎?
看看下面的代碼:它使用屬性而不是直接訪問實例變量。
如何在這種情況下重新排序?無論如何,它會發生嗎?或者只有當編譯器內聯訪問屬性時纔可能發生?
public class IfYouThinkYouUnderstandVolatileWithProps
{
private volatile int x, y;
public int PropX
{
get { return this.x; }
set { this.x = value; }
}
public int PropY
{
get { return this.y; }
set { this.y = value; }
}
private void Test1() // Executed on one thread
{
this.PropX = 1; // Volatile write (release-fence)
int a = this.PropY; // Volatile read (acquire-fence)
}
private void Test2() // Executed on another thread
{
this.PropY = 1; // Volatile write (release-fence)
int b = this.PropX; // Volatile read (acquire-fence)
}
}
'volatile'不會停止所有**重新排序。使用此關鍵字相同類型的操作仍然可以重新排序(如在寫入之前的兩個讀取和在讀取之前的兩個寫入)。 – VMAtm