多執行緒計數操作,共享狀態或者統計相關時間次數,這些都需要在多執行緒之間共享變數和修改變數,如此就需要在多線
程間對該變數進行互斥操作和訪問.我們譚老先生早都說過了! ++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...