天天看點

線程同步——核心對象實作線程同步——等待函數

1 對于核心對象實作線程同步,不得不提三點:
  2 1)大多數核心對象既有觸發也有未觸發兩個狀态
  3 比如:程序、線程、作業、檔案流、事件、可等待的計時器、信号量、互斥量
  4 2)等待函數:等待函數使線程自願進入等待狀态,直到指定的核心對象變為觸發狀态為止,
  5 說道等待我們最喜歡不過了,因為這樣不會浪費我們寶貴的CPU時間。
  6 3)對于自動重置對象來說,當對象被觸發時,函數會自動檢測到(手動重置對象為觸發是,函數也能檢測到),
  7 并開始執行,但是在函數會在傳回之前使事件變為非觸發狀态。
  8 
  9 下面介紹一下最常見的幾個等待函數:
 10 1):
 11 DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds );
 12 第一個參數hHandle用來辨別要等待的核心對象,第二個人參數dwMilliseconds用來辨別自願花多長時間等待。
 13 
 14 下面的函數是告訴系統,線程希望一直等待,直到線程所在的程序終止或hProcess辨別的對象變為觸發狀态
 15 WaitForSingleObject(hProcess,INFINITE);
 16 
 17 關于等待函數的傳回問題,我們看下面代碼:
 18 DWORD dw = WaitForSingleObject(hProcess,5000) ;
 19 
 20 switch(dw)
 21 {
 22 case WAIT_OBJECT_0:
 23     // 線程等待對象被觸發,也就是說線程還沒到5000的等待時間就開始工作啦
 24     break;
 25 
 26 case WAIT_TIMEOUT:
 27     //線程等待逾時,線程在5000的時間還是沒有等到對象被觸發,但是時間到了,線程也要開始工作啦
 28     break;
 29 
 30 case WAIT_FAILED:
 31     //線程傳人了一個無效的句柄,這時後果可能就無法預料了
 32     break;
 33 }
 34 
 35 2)
 36 DWORD WaitForMultipleObjects(
 37                    DWORD nCount, 
 38                    CONST * HANDLE  phObjects,
 39                    BOOL bWaitAll ,
 40                    DWORD dwMilliseconds) ;
 41 第一個參數nCount表示我們希望檢測核心對象的數量,這個值必須在 1到 MAXIMUM_WAIT_OBJECTS 最大是64,
 42 我相信已經夠多了,真的需要那麼多時就不應該用這種方法了哦
 43 第二個參數phObjects,是一個指針,指向核心對象句柄的數組
 44 第三個參數bWaitAll是告訴函數,我們希望用哪種方式。如果這個函數傳入 TRUE ,
 45 那麼在所有的核心對象被觸發之前,函數不會允許調用線程執行。
 46 第四個參數dwMilliseconds就是和WaitForSingleObject的第二個參數一樣了,我們最多等待多久,
 47 當然也可以傳入INFINITE表示在滿足條件前願意一直等待。
 48 
 49 關于WaitForMultipleObjects的傳回值,我們也一起來看看代碼哇:
 50 
 51 HANDLE h[3];
 52 h[0] = hProgress1 ;
 53 h[1] = hProgress2 ;
 54 h[2] = hProgress3 ;
 55 
 56 DWORD dw = WaitForMultipleObjects(3,h,FALSE,5000) ;
 57 switch(dw)
 58 {
 59 case WAIT_FAILED:
 60     //傳入無效句柄,後果就不多說了哈
 61     break;
 62 
 63 case WAIT_TIMEOUT:
 64     //線程等待逾時,線程在5000的時間還是沒有等到對象被觸發,但是時間到了,線程要開始工作啦
 65     break;
 66 
 67 case WAIT_OBJECT_0 + 0:
 68     //對象h[0]為觸發狀态
 69     break;
 70 
 71 case WAIT_OBJECT_0 + 1:
 72     //對象h[1]為觸發狀态
 73     break;
 74 
 75 case WAIT_OBJECT_0 + 2:
 76     //對象h[2]為觸發狀态
 77     break;
 78 }
 79 //這樣寫也有弊端,比如h[0] 和 h[1]同時為觸發時,結果h[0]處理完就傳回了
 80 把下面代碼DWORD WINAPI ThreadFunOne(PVOID pvParam) 線程中注釋行運作,便可以體會體會了。
 81 
 82 #include "windows.h"
 83 #include "iostream"
 84 using namespace std;
 85 long g_x = 0 ;
 86 
 87 // 定義一個事件對象1
 88 // HANDLE g_hEvent1 ;  
 89 // 
 90 // 定義一個事件對象2
 91 // HANDLE g_hEvent2;   
 92 
 93 HANDLE h[2];
 94 
 95 
 96 
 97 //定義線程函數1
 98 DWORD WINAPI ThreadFunOne(PVOID pvParam) ;
 99 
100 //定義線程函數2
101 DWORD WINAPI ThreadFunTwo(PVOID pvParam);
102 
103 int main()
104 {
105 
106 //建立一個手動重置的事件對象
107 h[0] = CreateEvent(NULL,FALSE,TRUE,NULL);
108 
109 //建立一個手動重置的事件對象
110 h[1] = CreateEvent(NULL,FALSE,TRUE,NULL);
111 
112 //把事件設為未觸發狀态
113 //    ResetEvent(g_hEvent);
114 
115 //建立線程1
116 HANDLE hThreadOne = CreateThread(NULL,0,ThreadFunOne,0,0,NULL);
117 CloseHandle(hThreadOne);
118 
119 //建立線程2
120 HANDLE hThreadTwo = CreateThread(NULL,0,ThreadFunTwo,0,0,NULL);
121 CloseHandle(hThreadTwo);
122 
123 //讓主線程先挂起,確定其它線程執行完成
124 Sleep(1000); 
125 cout<<g_x<<endl;
126 return 0 ;
127 }
128 
129 DWORD WINAPI ThreadFunOne(PVOID pvParam) 
130 {
131 WaitForMultipleObjects(2,h,FALSE,INFINITE) ; //運作結果為2
132 //WaitForMultipleObjects(2,h,TRUE,INFINITE) ; //運作結果為1
133 g_x++;
134 
135 return 0;
136 }
137 
138 DWORD WINAPI ThreadFunTwo(PVOID pvParam)
139 {
140 Sleep(200);
141 WaitForSingleObject(h[1],INFINITE);
142 g_x++;    
143 
144 return 0;
145 }
146        

轉載于:https://www.cnblogs.com/yfyzy/p/3916186.html