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
原文链接: https://www.cnblogs.com/poissonnotes/p/7681484.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/261384

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月14日 下午2:25
下一篇 2023年2月14日 下午2:25

相关推荐