【 聲明:著作權,歡迎轉載,請勿用於商業用途。 聯絡信箱: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之間出現了系統調度。所以,我們在編寫程式的時候必須有一個牢固的思想意識,如果缺少必須要的手段,程式可以任何時刻任何地點被調度,那此時公用資料的計算就會出現錯誤。
那麼有沒有方法避免這種情況的發生呢?當然有。朋友們可以繼續關注下面的部落格。