多線程的那點兒事(之資料同步)

來源:互聯網
上載者:User

【 聲明:著作權,歡迎轉載,請勿用於商業用途。  聯絡信箱:feixiaoxing @163.com】

    多線程建立其實十分簡單,在windows系統下面有很多函數可以建立多線程,比如說_beginthread。我們就可以利用它為我們編寫一段簡單的多線程代碼,

#include <windows.h>#include <process.h>#include <stdio.h>unsigned int value = 0;void print(void* argv){while(1){printf("&value = %x, value = %d\n", &value, value);value ++;Sleep(1000);}}int main(){    _beginthread( print, 0, NULL );_beginthread( print, 0, NULL);while(1) Sleep(0);return 1;}

    注意,在VC上面編譯的時候,需要開啟/MD開關。具體操作為,【project】->【setting】->【c/c++】->Category【Code Generation】->【Use run-time library】->【Debug Multithreaded】即可。

    通過上面的樣本,我們看到作為共用變數的value事實上是可以被所有的線程訪問的。這就是線程資料同步的最大優勢——方便,直接。因為線程之間除了堆棧空間不一樣之外,程式碼片段和資料區段都是在一個空間裡面的。所以,線程想訪問公用資料,就可以訪問公用資料,沒有任何的限制。

    當然,事物都有其兩面性。這種對公用資源的訪問模式也會導致一些問題。什麼問題呢?我們看了就知道了。

    現在假設有一個池塘,我們雇兩個人來餵魚。兩個人不停地對池塘裡面的魚進行餵食。我們規定在一個人餵魚的時候,另外一個人不需要再餵魚,否則魚一次喂兩回就要撐死了。為此,我們安裝了一個牌子作為警示。如果一個人在餵魚,他會把牌子設定為FALSE,那麼另外一個人看到這個牌子,就不會繼續餵魚了。等到這個人喂完後,他再把牌子繼續設定為TRUE。

    如果我們需要把這個故事寫成代碼,那麼怎麼寫呢?朋友們試試看,

while(1){if( flag == true){        flag = false;do_give_fish_food();flag = true;}Sleep(0);}

    上面的代碼看上去沒有問題了,但是大家看看代碼的彙編代碼,看看是不是存在隱患。因為還會出現兩個人同時餵食的情況,

23:       while(1){004010E8   mov         eax,1004010ED   test        eax,eax004010EF   je          do_action+56h (00401126)24:           if( flag == true){004010F1   cmp         dword ptr [flag (00433e04)],1004010F8   jne         do_action+43h (00401113)25:               flag = false;004010FA   mov         dword ptr [flag (00433e04)],026:               do_give_fish_food();00401104   call        @ILT+15(do_give_fish_food) (00401014)27:               flag = true;00401109   mov         dword ptr [flag (00433e04)],128:           }29:30:           Sleep(0);00401113   mov         esi,esp00401115   push        000401117   call        dword ptr [__imp__Sleep@4 (004361c4)]0040111D   cmp         esi,esp0040111F   call        __chkesp (004011e0)31:       }00401124   jmp         do_action+18h (004010e8)32:   }

    我們此時假設有兩個線程a和b在不停地進行判斷和餵食操作。設定當前flag = true,此時線程a執行到004010F8處時,判斷魚還沒有餵食,正準備執行指令004010F8,但是還沒有來得及對falg進行設定,此時出現了線程調度。線程b運行到004010F8時,發現當前沒有人餵食,所以執行餵食操作。等到b線程餵食結束,運行到00401113的時候,此時又出現了調度。線程a有繼續運行,因為之前已經判斷了當前還沒有餵食,所以線程a繼續進行了餵食了操作。所以,可憐的魚,這一次就連續經曆了兩次餵食操作,估計有一部分魚要撐死了。

    當然魚在這裡之所以會出現撐死的情況,主要是因為line 24和line 25之間出現了系統調度。所以,我們在編寫程式的時候必須有一個牢固的思想意識,如果缺少必須要的手段,程式可以任何時刻任何地點被調度,那此時公用資料的計算就會出現錯誤。

    那麼有沒有方法避免這種情況的發生呢?當然有。朋友們可以繼續關注下面的部落格。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.