[英]Why does this acquire and release memory fence not give a consistent value?
[英]Acquire/Release versus Sequentially Consistent memory order
對於任何std::atomic<T>
,其中T是原始類型:
如果我將std::memory_order_acq_rel
用於fetch_xxx
操作,而std::memory_order_acquire
用於load
操作,而std::memory_order_release
用於store
操作則是盲目的(我的意思是就像重置這些函數的默認內存順序一樣)
std::memory_order_seq_cst
(默認設置)相同? std::memory_order_seq_cst
有什么不同嗎? 用於原子操作的C ++ 11內存排序參數指定對排序的約束。 如果使用std::memory_order_release
進行存儲,並且另一個線程的負載使用std::memory_order_acquire
讀取值,則第二個線程的后續讀取操作將看到第一個線程之前存儲在任何內存位置的任何值。存儲版本, 或以后存儲到這些存儲位置中的任何一個 。
如果存儲和后續加載均為std::memory_order_seq_cst
則這兩個線程之間的關系相同。 您需要更多線程才能看到差異。
例如std::atomic<int>
變量x
和y
都初始為0。
線程1:
x.store(1,std::memory_order_release);
線程2:
y.store(1,std::memory_order_release);
線程3:
int a=x.load(std::memory_order_acquire); // x before y
int b=y.load(std::memory_order_acquire);
線程4:
int c=y.load(std::memory_order_acquire); // y before x
int d=x.load(std::memory_order_acquire);
如所寫,到x
和y
的存儲之間沒有關系,因此很有可能在線程3中看到a==1
, b==0
在線程4中看到c==1
和d==0
。
如果所有內存排序都更改為std::memory_order_seq_cst
則這將在存儲之間強制執行對x
和y
的排序。 因此,如果線程3看到a==1
且b==0
則這意味着x
的存儲必須在y
的存儲之前,因此,如果線程4看到c==1
,則意味着y
的存儲已完成,則y
存儲到x
還必須已完成,因此我們必須具有d==1
。
實際上,根據編譯器和處理器架構的不同,在各處使用std::memory_order_seq_cst
會給加載或存儲或兩者都增加額外的開銷。 例如,x86處理器的一種常用技術是為std::memory_order_seq_cst
存儲使用XCHG
指令而不是MOV
指令,以提供必要的排序保證,而對於std::memory_order_release
,則使用普通的MOV
就足夠了。 在具有更寬松的內存體系結構的系統上,開銷可能會更大,因為普通加載和存儲的保證較少。
內存排序很難。 我在書中幾乎花了整整一章。
內存排序可能非常棘手,而將其弄錯的影響通常非常微妙。
所有內存排序的關鍵點在於,它保證了“已發生”,而不是即將發生的事情。 例如,如果您將某物存儲到幾個變量中(例如x = 7; y = 11;
),那么另一個處理器可能會在看到y
中的值7
之前將y
視為11。 通過在設置x
和y
之間使用內存排序操作,您所使用的處理器將保證x = 7;
在繼續存儲y
之前已被寫入內存。
在大多數情況下,只要最終更新該值,寫的順序並不重要。 但是,例如,如果我們有一個帶整數的循環緩沖區,那么我們將執行以下操作:
buffer[index] = 32;
index = (index + 1) % buffersize;
而其他一些線程正在使用index
來確定已寫入新值,那么我們需要先寫入32
,然后在AFTER之后更新index
。 否則,另一個線程可能會獲取old
數據。
使信號量,互斥量等工作也同樣適用-這就是為什么術語“釋放”和“獲取”用於內存屏障類型的原因。
現在, cst
是最嚴格的排序規則-它強制您對已寫入的數據進行讀寫操作,然后再將它們存儲到內存中,然后處理器才能繼續執行更多操作。 這將比進行特定的獲取或釋放障礙要慢。 它迫使處理器確保存儲和加載已完成,而不是僅存儲或加載。
那有什么不同? 它高度依賴於系統架構是什么。 在某些系統上,緩存需要部分刷新,並且中斷從一個內核發送到另一個內核,並說“請在繼續之前進行此刷新工作”,這可能需要數百個周期。 在其他處理器上,它只比常規的內存寫入慢了一點點。 X86非常擅長快速執行此操作。 例如,某些類型的嵌入式處理器(某些型號的-不確定?)需要在處理器中做更多的工作才能確保一切正常。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.