日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

无锁编程[0]__多线程条件下的计数器__原子的加/减/与/或/异或操作__sync_fetch_and_add,__sync_add_and_fetch等

發(fā)布時間:2024/2/28 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 无锁编程[0]__多线程条件下的计数器__原子的加/减/与/或/异或操作__sync_fetch_and_add,__sync_add_and_fetch等 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

多線程條件下的計數(shù)器是服務器開發(fā)的常用操作,比如異步請求sessionid的活動,通常我們會用:

1、加鎖取sessionid

2、分段取sessionid (在初始化階段完成多線程分段取sessionid,這種使我們現(xiàn)在使用的方式,但是計數(shù)器是不能分段的)


當然我們知道,count++這種操作不是原子的。一個自加操作,本質(zhì)是分成三步的:
1、 從緩存取到寄存器
2、 在寄存器加1
3、 存入緩存。
由于時序的因素,多個線程操作同一個全局變量,會出現(xiàn)問題。這也是并發(fā)編程的難點。在目前多核條件下,這種困境會越來越彰顯出來。
最簡單的處理辦法就是加鎖保護,這也是我最初的解決方案。看下面的代碼:
pthread_mutex_t count_lock = PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_lock(&count_lock);
global_int++;
pthread_mutex_unlock(&count_lock);


后來在網(wǎng)上查找資料,找到了__sync_fetch_and_add系列的命令,發(fā)現(xiàn)這個系列命令講的最好的一篇文章,英文好的同學可以直接去看原文。Multithreaded simple data type access and atomic variables

__sync_fetch_and_add系列一共有十二個函數(shù),有加 /減 /與 /或 /異或 /等函數(shù)的原子性操作函數(shù),__sync_fetch_and_add,顧名思義,先fetch,然后自加,返回的是自加以前的值。以count = 4為例,調(diào)用__sync_fetch_and_add(&count,1),之后,返回值是4,然后,count變成了5。
有__sync_fetch_and_add,自然也就有__sync_add_and_fetch,這個的意思就很清楚了,先自加,在返回。他們哥倆的關系與i++和++i的關系是一樣的。

有了這個寶貝函數(shù),我們就有新的解決辦法了。對于多線程對全局變量進行自加,我們就再也不用理線程鎖了。下面這行代碼,和上面被pthread_mutex保護的那行代碼作用是一樣的,而且也是線程安全的。

__sync_fetch_and_add( &global_int, 1 );


下面是這群函數(shù)的全家福,大家看名字就知道是這些函數(shù)是干啥的了。
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);

需要提及的是,這個type不能夠瞎搞(type只能是int, long ,long long(及對應unsigned類型)。

?

下面看下__sync_fetch_and_add反匯編出來的指令,
804889d: f0 83 05 50 a0 04 08 lock addl $0x1,0x804a050
我們看到了,addl前面有個lock,這行匯編指令碼前面是f0開頭,f0叫做指令前綴,Richard Blum
老爺子將指令前綴分成了四類,有興趣的同學可以看下。其實我也沒看懂,intel的指令集太厚了,沒空看。總之老爺子解釋了,lock前綴的意思是對內(nèi)存區(qū)域的排他性訪問。
? Lock and repeat prefixes
? Segment override and branch hint prefixes
? Operand size override prefix
? Address size override prefix

前文提到,lock是鎖FSB,前端串行總線,front serial bus,這個FSB是處理器和RAM之間的總線,鎖住了它,就能阻止其他處理器或者core從RAM獲取數(shù)據(jù)。當然這種操作是比較費的,只能操作小的內(nèi)存可以這樣做,想想我們有memcpy ,如果操作一大片內(nèi)存,鎖內(nèi)存,那么代價就太昂貴了。所以前文提到的_sync_fetch_add_add家族,type只能是int long ,long long(及對應unsigned類型)。

?

性能上__sync_fetch_and_add,完爆線程鎖。
從測試結(jié)果上看, __sync_fetch_and_add,速度是線程鎖的6~7倍。

總結(jié)

以上是生活随笔為你收集整理的无锁编程[0]__多线程条件下的计数器__原子的加/减/与/或/异或操作__sync_fetch_and_add,__sync_add_and_fetch等的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。