原子計數操作 syn fetch and

2021-08-21 12:12:49 字數 2390 閱讀 1156

多執行緒計數操作,共享狀態或者統計相關時間次數,這些都需要在多執行緒之間共享變數和修改變數,如此就需要在多線

程間對該變數進行互斥操作和訪問.我們譚老先生早都說過了! ++i 和 i++都是不是原子性的,本質上為三步:

1. 從快取取到暫存器

2. 在暫存器中加1

3. 再存入快取

但是有時候由於時序的元素,多執行緒操作同乙個全域性變數,就會出現很多問題,這就是多執行緒併發程式設計的難點,尤其隨

著計算器硬體技術的快速發展,多cpu多核技術更是彰顯出這種困難.

其實最有效的方法就是加互斥量,後來在我們的c++11當中,提供了_syn_fetch_and_add一系列命令進行原子性操作,

_sync_fetch_and_add系列一共有12個函式,分別:加/減/與/或異或等原子性操作函式,_syn_fetch_and_add,顧明

思義,先fetch,返回自加前的值,舉例說明,count = 4,呼叫_sync_fetch_and_add(&count,1)之後,返回值是4,但

是count變成5. 同樣的 __sync_add_and_fetch,先自加,然後返回自加後的值,這樣對應的關係,與i++和++i的關係

是一樣的.   12個函式如下所示:

type __sync_fetch_and_add (type *ptr, type value, ...)

type __sync_fetch_and_sub (type *ptr, type value, ...)

type __sync_fetch_and_or (type *ptr, type value, ...)

type __sync_fetch_and_and (type *ptr, type value, ...)

type __sync_fetch_and_xor (type *ptr, type value, ...)

type __sync_fetch_and_nand (type *ptr, type value, ...)

type __sync_add_and_fetch (type *ptr, type value, ...)

type __sync_sub_and_fetch (type *ptr, type value, ...)

type __sync_or_and_fetch (type *ptr, type value, ...)

type __sync_and_and_fetch (type *ptr, type value, ...)

type __sync_xor_and_fetch (type *ptr, type value, ...)

type __sync_nand_and_fetch (type *ptr, type value, ...)

上述12個函式即為所有,通過函式名字就可以知道函式的作用,需要注意的是,這個type不能亂用(type 只能是int ,

long ,long long以及對應的unsigned的型別) . 這裡還有類似的原子操作:

bool __sync_bool_compare_and_swap(type *ptr, type oldval, type newval, ...)

type __sync_val_compare_and_swap(type *ptr, type oldval, type newval, ...)

這兩個函式提供院子的交換和比較,如果 *ptr == oldval,就將newval寫入 *ptr,第乙個函式在相等並寫入的情況下返

回true,第二個函式在返回操作之前的值.

有了這些裝逼利器,對於多執行緒對全域性變數進行操作(自加,自減)問題,我們就不用考慮執行緒鎖,可以考慮使用上述

函式代替和使用pthread_mutex保護的作用是一樣的,執行緒安全且效能完爆執行緒鎖.  那麼效能好在**呢 ?

下面簡單介紹一下 __syn_fetch_and_add反彙編出來的指令:

804889d:f0 83 05 50 a0 04 08 lock addl $0x1,0x804a050

可以看到,add前面有乙個lock,這行彙編指令前面是f0開頭,f0叫做指令字首,richard blum,lock字首的意思是對記憶體區

域的排他性訪問.、

其實,lock是鎖fsb,前端序列總行,front serial bus,這個fsb是處理器和ram直接的匯流排,鎖住fsb,就能阻止其他處

理器或core從ram獲取資料,當然這種操作開銷相當大,只能操作小的記憶體才可以這有做. 如果操作一大片記憶體,鎖記憶體

,那麼代價太大了,所以前面介紹__sync_fetch_and_add等函式,type只能是int long longlong以及對應的unsigned型別.

今後寫專案切記,加加減減出現競態現象的時候,一定要記起來使用這個函式!  看網上做實驗比mutex效能好.

原子性,原子操作

舉個例子 a想要從自己的帳戶中轉1000塊錢到b的帳戶裡。那個從a開始轉帳,到轉帳結束的這乙個過程,稱之為乙個事務。在這個事務裡,要做如下操作 從a的帳戶中減去1000塊錢。如果a的帳戶原來有3000塊錢,現在就變成2000塊錢了。在b的帳戶裡加1000塊錢。如果b的帳戶如果原來有2000塊錢,現在...

原子迴圈計數器

現實當中很多場景,需要進行輪訓服務,比如輪訓在10個日誌檔案當中寫日誌,在10臺機器上輪訓的去呼叫以實現負載均衡,常規的做法,如tomcat的poller執行緒輪訓選擇,就採用 math.abs pollerrotater.incrementandget pollers.length 此地需要取原子...

原子迴圈計數器

感謝同事 孫棋 的投稿 現實當中很多場景,需要進行輪訓服務,比如輪訓在10個日誌檔案當中寫日誌,在10臺機器上輪訓的去呼叫以實現負載均衡,常規的做法,如tomcat的poller執行緒輪訓選擇,就採用 1math.abs pollerrotater.incrementandget pollers.l...