c++中SetEvent和ResetEvent的使用


 

關於事件
  事件(Event)是WIN32提供的最靈活的線程間同步方式,事件可以處於激發狀態(signaled or true)或未激發狀態(unsignal or false)。根據狀態變遷方式的不同,事件可分為兩類:
  (1)手動設置:這種對象只可能用程序手動設置,在需要該事件或者事件發生時,采用SetEvent及ResetEvent來進行設置。
  (2)自動恢復:一旦事件發生並被處理后,自動恢復到沒有事件狀態,不需要再次設置。
  

創建事件的函數原型為:

 

HANDLE CreateEvent(
 LPSECURITY_ATTRIBUTES lpEventAttributes,
 // SECURITY_ATTRIBUTES結構指針,可為NULL
 BOOL bManualReset, 
 // 手動/自動
 // TRUE:在WaitForSingleObject后必須手動調用ResetEvent清除信號
 // FALSE:在WaitForSingleObject后,系統自動清除事件信號
 BOOL bInitialState, //初始狀態
 LPCTSTR lpName //事件的名稱
);

 

使用"事件"機制應注意以下事項:
  (1)如果跨進程訪問事件,必須對事件命名,在對事件命名的時候,要注意不要與系統命名空間中的其它全局命名對象沖突;
  (2)事件是否要自動恢復;
  (3)事件的初始狀態設置。

 

看下面代碼: 

 

  1 // event.cpp : 定義控制台應用程序的入口點。
  2 //
  3 
  4 #include "stdafx.h"
  5 #include <wtypes.h>
  6 #include <iostream>
  7 using namespace std;
  8 
  9 DWORD WINAPI ThreadProc(LPVOID lpParam);
 10 DWORD WINAPI ThreadProc2(LPVOID lpParam);
 11 
 12 DWORD g_dwThreadID;
 13 DWORD g_dwThreadID2;
 14 
 15 UINT g_nTickets = 300;  //int g_nTickets = 300;  //備注1  
 16 
 17 HANDLE g_hEvent1 = NULL;
 18 HANDLE g_hEvent2 = NULL;
 19 
 20 CRITICAL_SECTION g_cs;
 21 
 22 int ThreadCout = 0;
 23 
 24 int _tmain(int argc, _TCHAR* argv[])
 25 {
 26     cout << "Main thread is running." << endl;
 27 
 28     InitializeCriticalSection(&g_cs);//初始化臨界區  
 29 
 30     HANDLE hHandle = CreateThread(NULL, 0, ThreadProc, NULL, 0, &g_dwThreadID);
 31     ThreadCout++;
 32     HANDLE hHandle2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, &g_dwThreadID2);
 33     ThreadCout++;
 34 
 35     g_hEvent1 = CreateEvent(NULL, FALSE, TRUE, NULL);  //備注5:g_hEvent1 = CreateEvent(NULL, TRUE,  TRUE, NULL);  
 36     g_hEvent2 = CreateEvent(NULL, FALSE, TRUE, NULL);  //備注5:g_hEvent2 = CreateEvent(NULL, TRUE,  TRUE, NULL);  
 37 
 38     ResetEvent(g_hEvent1);
 39     ResetEvent(g_hEvent2);
 40 
 41     SetEvent(g_hEvent1);
 42 
 43 
 44     while (TRUE)
 45     {
 46         EnterCriticalSection(&g_cs);
 47         int nCount = ThreadCout;
 48         LeaveCriticalSection(&g_cs);
 49 
 50         if (nCount == 0)
 51         {
 52             cout << "Main thread is break." << endl;
 53             break;
 54         }
 55 
 56     }
 57 
 58 
 59     Sleep(1000);    //備注4     
 60 
 61     CloseHandle(hHandle);
 62     CloseHandle(hHandle2);
 63 
 64     DeleteCriticalSection(&g_cs);
 65 
 66     cout << "Main thread is end." << endl;
 67 
 68     system("pause");
 69     return 0;
 70 }
 71 
 72 
 73 DWORD WINAPI ThreadProc(LPVOID lpParam)
 74 {
 75     // cout << "No." << g_dwThreadID << " thread is running." << endl;    
 76     while (TRUE)
 77     {
 78         WaitForSingleObject(g_hEvent1, INFINITE);
 79         cout << "No.1 " << g_dwThreadID << " thread is running." << endl;
 80 
 81         EnterCriticalSection(&g_cs);
 82         int temp = g_nTickets;
 83         LeaveCriticalSection(&g_cs);
 84 
 85         cout << "No.1 " << g_dwThreadID << " thread is temp." << endl;
 86 
 87         if (temp > 0)
 88         {
 89             Sleep(10);  //Sleep(1000)   //備注2  
 90             cout << "No.1-" << g_dwThreadID << " sell ticket : " << temp << endl;
 91 
 92 
 93             EnterCriticalSection(&g_cs);
 94             g_nTickets--;
 95             LeaveCriticalSection(&g_cs);
 96 
 97             SetEvent(g_hEvent2);
 98             //ResetEvent(g_hEvent1);//備注6  
 99         }
100         else
101         {
102             cout << "No.1- break" << endl;
103             //ResetEvent(g_hEvent1);//備注6  
104             SetEvent(g_hEvent2);//沒有這個ThreadProc2不能終止   //備注3  
105             break;
106         }
107     }
108 
109     EnterCriticalSection(&g_cs);
110     ThreadCout--;
111     LeaveCriticalSection(&g_cs);
112     cout << "No.1- end" << endl;
113 
114     return 0;
115 }
116 
117 DWORD WINAPI ThreadProc2(LPVOID lpParam)
118 {
119     //   
120     while (TRUE)
121     {
122         WaitForSingleObject(g_hEvent2, INFINITE);
123         cout << "No.2 " << g_dwThreadID2 << " thread is running." << endl;
124 
125         EnterCriticalSection(&g_cs);
126         int temp = g_nTickets;
127         LeaveCriticalSection(&g_cs);
128 
129         if (temp > 0)
130         {
131             Sleep(10);  //Sleep(1000)   //備注2  
132             cout << "No.2-" << g_dwThreadID2 << " sell ticket : " << temp << endl;
133 
134             EnterCriticalSection(&g_cs);
135             g_nTickets--;
136             LeaveCriticalSection(&g_cs);
137 
138             SetEvent(g_hEvent1);
139             //ResetEvent(g_hEvent2);//備注6  
140         }
141         else
142         {
143             cout << "No.2- break" << endl;
144             //ResetEvent(g_hEvent2);//備注6  
145             SetEvent(g_hEvent1);//同樣的問題,沒有這個ThreadProc不能終止      //備注3  
146             break;
147         }
148     }
149 
150     EnterCriticalSection(&g_cs);
151     ThreadCout--;
152     LeaveCriticalSection(&g_cs);
153 
154     cout << "No.2- end" << endl;
155     return 0;
156 }

 

這個代碼是接上一遍關於UINT類型作為循環變量的不確定性問題繼續完善的,加入了臨界區控制全局變量的訪問。

本文要說明的是SetEventResetEvent的使用,這個要看備注5和備注6

備注5處:

CreateEvent的第二個參數決定了是否需要手動調用ResetEvent,當為TRUE時,是需要手動調用,如果不調用,會怎么樣呢?不調用,事件會處於一直有信號狀態,即備注6處。當為FALSE時候,不需要手動調用,調用不調用,效果一樣。把ResetEvent放在WaitForSingleObject前面也是很好的做法。

 

轉載請注明原創鏈接:http://blog.csdn.net/wujunokay/article/details/12272581


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM