int linux 原子操作_linux c++编程之多线程:原子操作如何解决线程冲突
在多線程中操作全局變量一般都會引起線程沖突,為了解決線程沖突,引入原子操作。
1.線程沖突
#include #include #include #include int g_count = 0;void count(void *p){Sleep(100); //do some work//每個線程把g_count加1共10次for (int i = 0; i < 10; i++){g_count++;}Sleep(100); //do some work}int main(void){printf("******多線程訪問全局變量演示***by David***");//共創建10個線程HANDLE handles[10];for (int i = 0; i < 10; i++){for (int j = 0; j < 10; j++){handles[j] = _beginthread(count, 0, NULL);}WaitForMultipleObjects(10, handles, 1, INFINITE);printf("%d time g_count = %d", i, g_count);//重置g_count = 0;}getchar();return 0;}運行
理論上,g_count的最后結果應該是100,可事實卻并非如此,不但結果不一定是100,而且每次的結果還很可能不一樣。原因是,多個線程對同一個全局變量進行訪問時,特別是在進行修改操作,會引起沖突。詳細解釋:
設置斷點,查看反匯編
g_count++;被分為三步操作:
1.把g_count的內容從內存中移動到寄存器eax
2.把寄存器eax加1
3.把寄存器eax中的內容移動到內存g_count的地址
三步以后,g_count的值被順利加1。
cpu執行的時間片內包含多條指令,每條指令執行期間不會被打斷,但如果一個操作包含多條指令,則很有可能該操作會被打斷。g_count++;就是這樣的操作。
g_count被順利加到100的前提:每次加1,都建立在上一次加1順利完成的基礎上。也就是說,如果上一次加1被打斷,這一次的加1就得不到上一次加1的累積效果。自然,最后的結果,多半會小于100。
2.原子操作
所謂原子操作,是指不會被線程調度機制打斷的操作,操作一旦開始,就得執行到結束為止。原子操作可以是一個步驟,也可以是多個操作步驟,但是其順序是不可以被打亂,或者切割掉只執行部分。原子操作一般靠底層匯編實現。
在頭文件winnt.h中提供了很多的原子操作函數,它們使用自加鎖的方式,保證操作的原子性,如自增操作
InterlockedIncrement,
函數原型
LONG CDECL_NON_WVMPURE InterlockedIncrement(
_Inout_ _Interlocked_operand_ LONG volatile *Addend
);
其它相關操作,請自行查看頭文件。
使用該函數,我們修改線程函數count。修改很簡單,只需把g_count++改為InterlockedIncrement((LONG)&g_count);即可。
運行如下
顯然,在原子操作下,我們肯定是可以得到正確結果的。
需要C/C++ Linux服務器架構師學習資料私信“資料”(資料包括C/C++,Linux,golang技術,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK,ffmpeg等),免費分享
總結
以上是生活随笔為你收集整理的int linux 原子操作_linux c++编程之多线程:原子操作如何解决线程冲突的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SVM之交叉验证【转】
- 下一篇: 更新10_linux,时隔十年,QQ更新