Contributed by < huang-me
>
以下使用 gcc -O3 optimization
v_ready
定義為 amtomic_bool 則 compiler 將會插入 memory fence 使得所有在之前寫入的 register 值都被更新至 memory 中。
atomic_bool
,compiler 會對 while loop 中的讀取進行優化,造成無限迴圈而無法正常執行。(row 7,8)C/C++ 中分別定義atomic_is_lock_free
/std::atomic<T>::is_lock_free
可用以檢驗此 atomic 變數是否可以在 lock free 的情況下做到 atomic operation。
以上測試程式執行結果如下:
當需要 atomically 完成讀取、修改、寫入的一系列指令時,可以使用以下指令
atomic_<type>
: atomic_compare_exchange
& atomic_exchange
atomic_flag
: atomic_flag_test_and_set
& atomic_flag_clear
atomic_flag
實作 mutex lockatomic_flag
編譯結果atomic_flag_test_and_set
使用 x86 的 exchange 指令 xchgb
設定 flag 的值
atomic_flag_clear
則在寫入值之後還加上了 memory fence 以確保所有值的修改都可以被其他 processor 看見。
第 7 行中,lock
使得在做 cmpxchgl
時同時只能有一個 cpu 獲得此變數的存取權。
並且 cmpxchgl
先比較 %eax
以及 destination register (ai(%rip
),值相等時才將 %edx
中的值與 ai(%rip)
互換。
在某些 cpu 架構之下(MIPS,RISC-V,ARM,etc…),有指令可以追蹤此次要 store 的目標值是否被修改過,以避免 load modfiy store 覆蓋已經被更新的值。
atomic_compare_exchange_weak
存在意義我們可能經常使用以上方式進行 CAS 動作,但是如果硬體有支援 ll/sc 的話則有可能錯誤發生在 sc 而非一開始比較 val
以及 expected
時,但其時我們不在乎什麼時候出現錯誤,所以定義 weak 版本的 CAS 只要動作沒有正確的完成就會回傳 true。
有時候我們並不需要所有的指令都在一定的順序下執行,有部分的指令可以提前或者延後執行時間。
因此,在 stdatomic.h
中有 6 種 memory ordering model 可以讓 compiler 清楚各指令可以接受的優化方向。
在各個 thread 中,所有的指定為 memory_order_seq_cst
指令都是 sequentially 執行,所有的執行順序跟程式被撰寫的順序相同,因此沒有重排指令造成執行結果錯誤的可能性。
若同時讓多個 thread 執行以上 function,指令的執行順序按照 thread 建立時間以及指令順序執行。
使用 sequentially consistent 的缺點為即使使用多個 thread 還是按照 sequential 執行,使得執行效率低落,甚至可能跟 single thread 時差不多,但卻浪費了很多資源。
只能用在 atomic_load
所有在此 load 之後的指令都不能被重排到此指令的前面。
只能用在 atomic_store
與 Acquire 相反,所有在此 store 之前的指令都不能被重排到此指令的後面。
可以用在 atomic_load
以及 atomic_store
必須同時滿足 Acquire 以及 Release 條件
所有 atomic operation 都 atomically 執行,但是不同 thread 之間對於相同變數的執行順序沒有固定。
基本上跟 Acquire
相似,不同點在於只需要保證相同變數的順序,其他不相關的變數可以做前後順序的調換,且 memory barrier 的加入為非必要。
〈Atomic Primer〉勘誤
應修正為:
"They look and act just like the type they mirror …"