*2023/06/21*
重新认识事件对象的使用
事件对象按用途分为两种:通知型和同步型。通知型的作用相当于一对多,一个线程可以通过通知型事件告诉多个其他等待该事件的线程我准备好了,或者类似的作用;而同步型事件则相当于一对一,一个时间点上只有一个线程可以占有该事件对象,其他线程需要等待,从而实现线程间的同步。以下示例,演示了这两种事件对象的使用:三个线程等待通知型事件对象,等到有信号之后,三个线程同步按顺序打印字符数组中的数据,每个线程打印不同类型的字符。代码如下:
#include<stdio.h>
#include<Windows.h>
HANDLE hNotificationEvent = INVALID_HANDLE_VALUE;
HANDLE hSynchronizationEvent = INVALID_HANDLE_VALUE;
char dataChar[MAX_PATH] = "jk12d3!@u#a$b7c";
enum char_type {
char_num,
char_char,
char_spec
};
BOOLEAN checkType(char chr, int charType)
{
BOOLEAN result = FALSE;
//字符型
//a~z
if (charType == char_char)
{
if (
chr >= 'a'
&&chr <= 'z'
)
{
result = TRUE;
}
}
else if (charType == char_num)//数字型 0~9
{
if (
chr >= '0'
&& chr <= '9'
)
{
result = TRUE;
}
}
else if(charType==char_spec)//其他特殊字符
{
if (
(chr >= 'a' &&chr<='z')
|| (chr >='0' &&chr<='9')
)
{
result = FALSE;
}
else
{
result = TRUE;
}
}
return result;
}
char popChar(char* data,int charType)
{
char result = 0x0;
int i = 0;
int strLength = 0;
strLength = (int)strlen(data);
do
{
//检查字符数组的长度
//是否有数据需要处理
if (0 == strLength)
break;
//对比当前字符与处理字符线程所需要的类型是否一致
//如果一致,将其从数组中移除
//否则,退出
if (FALSE == checkType(data[0], charType))
break;
if (strLength > 1)
{
//如果字符数组中的数据长度大于1
//移除第一个字符,后续字符依次前移一位
result = data[0];
//pop char from data
for (i = 0; i < strLength - 1; i++)
{
data[i] = data[i + 1];
}
//
data[i] = 0x0;
}
else if (strLength == 1)
{
//如果只有一个字符
//直接输出
result = data[0];
data[0] = 0x0;
}
} while (FALSE);
return result;
}
void printChar(int charType)
{
char result = 0x0;
//wait for synchronization event
do
{
//通过同步类型的事件来实现线程间的同步操作
//全局共享的字符资源
WaitForSingleObject(hSynchronizationEvent, INFINITE);
//根据字符类型决定释放打印当前第一个字符
//如果打印,该字符会从字符数组中移除
result = popChar(dataChar,charType);
if (result)
{
printf("tid:%d,char:%c\n", GetCurrentThreadId(), result);
}
else if(0==strlen(dataChar))
{
printf("no more data!\n");
SetEvent(hSynchronizationEvent);
break;
}
//将同步事件对象设置为有信号状态
//接着处理其他字符数据
SetEvent(hSynchronizationEvent);
} while (strlen(dataChar));
}
DWORD ThreadRoutine1(void* param)
{
DWORD result = WaitForSingleObject(hNotificationEvent, INFINITE);
printf("wait result:%d\n", result);
//这个线程打印数字类型的字符
printChar(char_num);
return 0;
}
DWORD ThreadRoutine2(void* param)
{
DWORD result = WaitForSingleObject(hNotificationEvent, INFINITE);
printf("wait result:%d\n", result);
//这个线程打印字符型的字符
printChar(char_char);
return 0;
}
DWORD ThreadRoutine3(void* param)
{
DWORD result=WaitForSingleObject(hNotificationEvent, INFINITE);
printf("wait result:%d\n", result);
//打印特殊字符
printChar(char_spec);
return 0;
}
void testevent()
{
//创建通知类型的事件对象
//初始状态为无信号
hNotificationEvent = CreateEventA(NULL, TRUE, FALSE, "testevent_notification");
//创建同步类型的事件对象
//初始状态为无信号
hSynchronizationEvent = CreateEventA(NULL, FALSE, FALSE, "testevent_synchronization");
if (
INVALID_HANDLE_VALUE != hNotificationEvent
&&INVALID_HANDLE_VALUE!=hSynchronizationEvent
)
{
//设置通知事件对象为有信号状态
SetEvent(hNotificationEvent);
CreateThread(NULL, 0, ThreadRoutine1, NULL, 0, NULL);
CreateThread(NULL, 0, ThreadRoutine2, NULL, 0, NULL);
CreateThread(NULL, 0, ThreadRoutine3, NULL, 0, NULL);
//设置同步类型的事件为有信号状态
SetEvent(hSynchronizationEvent);
}
//if (INVALID_HANDLE_VALUE != hEvent)
//{
// CloseHandle(hEvent);
//}
}
void testsync()
{
testevent();
}
------------------------------------------------------------------------------------------------------------------------------
---
Event 事件通常会用来控制同步操作,通俗地说就是一个流程中下一步操作会等待上一步操作结束才开始。下面是个简单的例子:
创建事件对象
#define event_name "shared_event"
int main()
{
int time=100;
HANDLE event=NULL;
event=CreateEvent(NULL,TRUE,FALSE,event_name);//创建初始状态为nonsingaled可手动设置的 事件
if(event!=INVALID_HANDLE_VALUE)
{
while(time--)
{
switch(WaitForSingleObject(event,3000))//设置等待时间为3秒,如果超时或者事件被设置为singaled就返回
{//注意下面case是WaitForSingleObject()返回值,不是GetLastError()的 返回值
case WAIT_OBJECT_0://在3秒内,事件被设置为由信号,可以进行下一步操作
//to do someting
ResetEvent(event);//这里一定要重新将状态为singaled设置为nonsingaled
printf("the event is set to singled.\n");
break;
case WAIT_TIMEOUT://3秒过了,事件没有被设置成有信号状态
//to do someting
printf("the WaitForSingleObject timekout elapsed.\n");
break;
default:
{
printf("an error:0x%x!\n",GetLastError());
goto retu;
}
}
}
}
else
{
printf("CreateEvent last error:0x%x\n",GetLastError());
}
retu:
if(event!=INVALID_HANDLE_VALUE)
CloseHandle(event);
return 0;
}
打开事件对象
event=OpenEvent(GENERIC_READ|GENERIC_WRITE,FALSE,event_name);
if(event==INVALID_HANDLE_VALUE)
{
//完成某个操作后,设置事件为singaled状态
SetEvent(event);
CloseHandle(event);
}