windows多線程(三) 原子操作

來源:互聯網
上載者:User

標籤:create   因此   src   return   init   c++   這一   計算   應該   

一、分析上一篇程式的現象

我們先從上一篇文章中的最後一個程式開始分析。

#include <stdio.h>#include <windows.h>const unsigned int THREAD_NUM = 10;DWORD WINAPI  ThreadFunc(LPVOID);int main(){    printf("我是主線程, pid = %d\n", GetCurrentThreadId());  //輸出主線程pid    HANDLE hThread[THREAD_NUM];    for (int i = 0; i < THREAD_NUM; i++)    {        hThread[i] = CreateThread(NULL, 0, ThreadFunc, &i, 0, NULL); // 建立線程    }        WaitForMultipleObjects(THREAD_NUM,hThread,true, INFINITE);  //一直等待,知道所有子線程全部返回    return 0;}DWORD WINAPI  ThreadFunc(LPVOID p){    int n = *(int*)p;    Sleep(1000*n);  //第 n 個線程睡眠 n 秒    printf("我是, pid = %d 的子線程\n", GetCurrentThreadId());   //輸出子線程pid    printf(" pid = %d 的子線程退出\n\n", GetCurrentThreadId());   //延時10s後輸出    return 0;}

看程式的輸出:

按照正常情況來看應該是每一行輸出兩列,但是中間有一行多出了一列,看圖中圈出來的地方,pid = 208 的線程輸出線程pid後並沒有馬上退出,而是等到了最後才退出。(可能每次啟動並執行情況不一樣,這裡只說明這一種情況),這是為什麼的。 這裡涉及到了線程調度的問題, 說明pid = 208 的線程輸出線程pid後作業系統進行了線程調度,cpu資源被其它線程搶佔,這個線程直到最後才又重新分配到cpu資源,重新往下執行。

二、原子操作

這裡明明是要寫原子操作,但是到目前為止,並沒有任何地方提及什麼是原子操作,不要著急,接下來就慢慢來說。那麼什麼是原子操作呢?一個操作如果能夠不受中斷地完成,我們稱之為原子操作

我們來看這個程式

#include <stdio.h>#include <windows.h>const unsigned int THREAD_NUM = 50;unsigned int g_Count = 0;DWORD WINAPI  ThreadFunc(LPVOID);int main(){    HANDLE hThread[THREAD_NUM];    for (int i = 0; i < THREAD_NUM; i++)    {        hThread[i] = CreateThread(NULL, 0, ThreadFunc, 0, 0, NULL); // 建立線程    }    WaitForMultipleObjects(THREAD_NUM, hThread, true, INFINITE);    //一直等待,直到所有子線程全部返回    printf(" 總共 %d 個線程給 g_Count 的值加一,現在 g_Count = %d\n", THREAD_NUM, g_Count);    return 0;}DWORD WINAPI  ThreadFunc(LPVOID p){    Sleep(50);    g_Count++;    Sleep(50);        return 0;}

有一個全域變數 g_Count ,每個線程給這個全域變數加一,照這麼來看最後應該輸出 50 ,我們看一下程式的輸出(每次都可能不一樣的結果)

為什麼會這樣呢??? 明明有 50 個線程都給 g_Count 加一了,為什麼輸出 46,根源在於 g_Count++; 這條語句上,這裡就只有一條c++語句,按理說不應該有問題,其實不然,現在,在這裡打下斷點,開始調試,開啟反組譯碼視窗(Vs編譯器快速鍵 Alt+8),如

可以看到,這一條c++語句,被分成了三條彙編語句,先是把 g_Count 的值給寄存器 eax,然後寄存器 eax 的值加一,再把 eax 的值給 g_Count ,這樣就完成一次 g_Count++ 操作。出問題的原因就在於,在這幾條彙編語句執行的過程中發送了線程切換,比如,A線程剛執行完 add eax,1 還沒有把 eax的值給 g_Count,這時B線程開始執行,把 g_Count 原先的值又存入 eax,這就修改了 eax 中A線程計算好的值。

因此在多線程環境中對一個變數進行讀寫時,我們需要有一種方法能夠保證對一個值的遞增操作是原子操作——即這個操作不可以被打斷性,一個線程在執行原子操作時,其它線程必須等待它完成之後才能開始執行該原子操作。Windows系統為我們提供了一些以Interlocked開頭的函數來完成這一任務。這裡只是介紹原子操作的概念,這和線程同步息息相關,但是這些以 以Interlocked 開頭的函數我們基本不用,就不一一介紹了,感興趣的可以自己去瞭解。

windows多線程(三) 原子操作

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.