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

posted @ 2017-10-17 14:29  poisson_notes  阅读(19770)  评论(0编辑  收藏  举报