2014-02-21 23 views
0

如果我在一個線程上創建一個變量,然後使用ManualResetEventWaitOne()方法阻塞,直到另一個線程將一個值分配給同一變量併發信號給EventWaitHandel。當我在第一個線程上讀取變量時,我保證始終獲得由其他線程分配的值?我擔心由於某些優化,我無法從CPU緩存中獲取值,因爲據我所知,我沒有使用任何內存障礙。)。如果使用EventWaitHandel,從另一個線程讀取時是否從一個線程「線程安全」分配了變量?

例如

var str = "multi-threading is hard!"; 
var mre = new ManualResetEvent(false); 
Task.Factory.StartNew(() => 
    { 
     str = Console.ReadLine(); 
     mre.Set(); 
    )); 
mre.WaitOne(); 
Console.WriteLine(str); 
+0

你說你會用'的WaitOne ()'。哪裏?我希望它在Console.WriteLine之前。 – Georg

+0

是的,感謝那 – markmnl

回答

1

那些指令將不被重新排序,這意味着,在產生螺紋上,該字段分配總會發生前手柄被髮信號通知,並且,在消耗螺紋上,該字段將總是後讀手柄發出信號。

如果有這兩對指令可以被重新排序(例如,如果第二個線程可以讀取句柄信號前場),那麼你就不會看到正確的值。

WaitOne()引入了隱式內存屏障,爲您提供所需的獲取釋放語義。

布賴恩·基甸和漢斯帕桑特放在一起的幾個類在.NET框架,引入內隱記憶障礙的一個很好的列表:Memory barrier generators

更多信息:Acquire and release semantics/Acquire and release fences

+0

我沒有看到這裏的重新排序的相關性,但內存屏障隱含清除它! – markmnl

+0

啊,順便謝謝你怎麼知道指令不能重新排序 - 是因爲內存障礙? – markmnl

+0

@markmnl我編輯了我的第一段,解釋了爲什麼重新排序是相關的。 – dcastro

0

你的變量是一個捕獲的變量,即,編譯器開啓這個局部變量成編譯器生成的類的字段,因爲你在lambda表達式使用它。 Afaik,這些編譯器生成的字段沒有標記爲volatile,所以它們可以被緩存。

編輯:的確,該字段不易變。

你完全可以通過編寫自己的類來防止緩存,以便編譯器不必創建一個類。但是,這當然會妨礙代碼的簡潔性。

+0

是的,我知道它被捕獲,但如果重寫與我自己的類的問題,問題仍然存在 - 我可以標記它在'volatile'。無論如何,似乎內存屏障是隱含的,所以沒有必要。 – markmnl

相關問題