"Loads are not reorderd with other loads" is a FACT!! 續:不要指望 volatile
上一篇隨筆中提到了volatile,實際上由于上一篇中提到的問題,volatile已經越來越遠離其應有的含義了。在說這個問題之前,我們又要提.NET的內存模型問題(以下簡稱MM),我不指望在這里長篇大論的說其內存模型是如何的。簡單的說就是以下的幾句話:
第一、load與store之間的數據依賴關系不會被改變
第二、所有的store操作都有release語義,所有的volatile的load都有acquire語義,
第三、所有的load與store都不能跨越memory barrier(full fence,全內存柵欄)
第四、load和store僅僅在緊鄰的對于相同位置的load和store存在時才可能被移除。
所謂acquire與release是怎么一回事,這個~acquire可以理解為,沒有其他的操作(對內存的)可以將自己執行的順序調整到它之前;相反的,release可以理解為,沒有其他的操作可以將自己的執行調整到它之后。但是請注意!acquire和release已經是半個內存柵障了!他應該對CPU的可見性產生影響。好,我們先不提這個,假設MS目前的x86, x64上的.NET的MM是完美實現的。看看MSDN對volatile的解釋是什么:
第一句:
The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time.
這句實際上沒有說任何的實際內容。
第二句:
Fields that are declared volatile are not subject to compiler optimizations that assume access by a single thread.
這句指出了volatile的一個作用--防止編譯器優化你的代碼,雖然提到了編譯器對于volatile不再認為是單線程訪問的,但是僅僅是assume,這并不能解決任何問題。
第三句:
This ensures that the most up-to-date value is present in the field at all times.
這是什么?這完全說明了我們上面所說的volatile的作用:volatile的load具有release語義!
第四句:
The volatile modifier is usually used for a field that is accessed by multiple threads without using the lock statement to serialize access.
實際上他想說,如果你向volatile中執行了store,那么你在load中(即使在另一個線程)也會獲得most up to date的值。這樣我們就不必使用lock再引入同步或者memory fence了。
好了,按照上面的解釋,如果.NET的MM是完美實現了的,OK,全部說得過去!但是請看上一篇隨筆,不是的!volatile根本不能保證load是acquire的!也就是,Microsoft的.NET Framework在x86與Intel 64的平臺下的實現是有漏洞的(這跟Intel一點沒有關系,不要誤會,是.NET的MM的問題)!因此,不要指望MSDN的解釋了。在你書寫Multi-thread Application的時候,還是多留一個心眼吧。
如果要修補這個漏洞,那么volatile的load需要半個memory fence,但是請看看x86,x64的文檔,你就知道,這里不得不要一個full fence。也就是,volatile的load是完全不會被reorder的,這合適么?我不知道,我不知道真正的Java MM的官方解釋在哪里,但是目前至少有文檔表明,Java的volatile是一個full fence。
最后,我想說明一點。大部分戰友們,大部分時間內,根本不用為這個操心勞神。Please don't be panic:-)
上一篇隨筆中提到了volatile,實際上由于上一篇中提到的問題,volatile已經越來越遠離其應有的含義了。在說這個問題之前,我們又要提.NET的內存模型問題(以下簡稱MM),我不指望在這里長篇大論的說其內存模型是如何的。簡單的說就是以下的幾句話...
浙公網安備 33010602011771號