多线程同步之Event(事件对象)

多线程与Event同步
本文介绍了一个使用Windows API进行多线程编程的例子,重点展示了如何利用AutoEvent和ManualEvent两种不同类型的Event对象来实现线程间的同步。通过创建六条线程并使用Event对象控制它们的启动和执行顺序,演示了Event对象的基本使用方法。

//多线程同步

//Event的应用
#define WIN32_LEAN_AND_MEAN
#include <STDIO.H>
#include <stdlib.h>
#include <WINDOWS.H>
#include "MtVerify.h"

//①创建Event事件句柄
HANDLE Auto_hEvent,Manual_hEvent;  //Auto类型的事件句柄,Manual类型的事件句柄

HANDLE hThread1,hThread2,hThread3;  //6个线程句柄
HANDLE hThread4,hThread5,hThread6;
DWORD ThreadId1,ThreadId2,ThreadId3; //6个线程的线程ID
DWORD ThreadId4,ThreadId5,ThreadId6; 
DWORD ExitCode1,ExitCode2,ExitCode3; //6个线程的线程退出码
DWORD ExitCode4,ExitCode5,ExitCode6;

DWORD WINAPI ThreadFunc1(LPVOID);  //线程函数1的定义
DWORD WINAPI ThreadFunc2(LPVOID);  //线程函数2的定义

int main()
{

 //②创建Event对象
 //AutoEvent表示event变成激发状态之后,自动重置为非激发状态
 //但不能自动的从非激发状态变成激发状态,这个是由程序自行操作的SetEvent
 MTVERIFY(Auto_hEvent = CreateEvent(
  NULL,     //默认安全属性
  FALSE,     //若FALSE,表示event变成激发状态之后,自动重置为非激发状态。若是TRUE表示不会自动重置
  FALSE,     //若TRUE,表示一开始处于激发状态,如为FALSE则表示一开始处于非激发状态
  "AutoEventName"   //Event对象名称,任何线程或进程都可以根据这个文字名称使用这个event对象
  ));

 //ManualEvent表示event变成激发状态之后,不会自动重置为非激发状态,
 //必须调用ResetEvent函数使其重置为非激发状态
 //同AutoEvent一样,也不能自动从非激发状态变成激发状态,必须调用SetEvent才能从非激发状态转变为激发状态
 MTVERIFY(Manual_hEvent = CreateEvent(NULL,TRUE,FALSE,"ManualEventName"));
 
 //创建6个线程
 MTVERIFY(hThread1 = CreateThread(NULL,0,ThreadFunc1,(LPVOID)1,NULL,&ThreadId1));
 MTVERIFY(hThread2 = CreateThread(NULL,0,ThreadFunc1,(LPVOID)2,NULL,&ThreadId2));
 MTVERIFY(hThread3 = CreateThread(NULL,0,ThreadFunc1,(LPVOID)3,NULL,&ThreadId3));
 MTVERIFY(hThread4 = CreateThread(NULL,0,ThreadFunc2,(LPVOID)4,NULL,&ThreadId4));
 MTVERIFY(hThread5 = CreateThread(NULL,0,ThreadFunc2,(LPVOID)5,NULL,&ThreadId5));
 MTVERIFY(hThread6 = CreateThread(NULL,0,ThreadFunc2,(LPVOID)6,NULL,&ThreadId6));

 //③设置Event为激发状态
 //因为在创建Event对象时,设定为创建非激发状态的事件对象
 //若想让等待这些事件对象的线程有机会执行,先要把事件对象设为激发状态
 SetEvent(Manual_hEvent); //设置为激发状态
 SetEvent(Auto_hEvent);  //设置为激发状态

 //若Event对象为ManualEvent(手动重置事件对象)
 //PulseEvent把Event对象设为激发状态
 //唤醒所有等待此Event对象的线程
// PulseEvent(Manual_hEvent);

 //若Event对象为AutoEvent(自动重置事件对象)
 //PulseEvent把Event对象设为激发状态
 //唤醒“一个”等待此Event对象的线程
// PulseEvent(Auto_hEvent);

 //获取6个线程的退出码
 GetExitCodeThread(hThread1,&ExitCode1);
 GetExitCodeThread(hThread2,&ExitCode2);
 GetExitCodeThread(hThread3,&ExitCode3);
 GetExitCodeThread(hThread4,&ExitCode4);
 GetExitCodeThread(hThread5,&ExitCode5);
 GetExitCodeThread(hThread6,&ExitCode6);

 //休眠2s等待线程执行结束
 Sleep(2000);

 //分别打印6个线程的退出码与线程ID
 printf("线程1的退出码:%ld,线程ID:%ld\n",ExitCode1,ThreadId1);
 printf("线程2的退出码:%ld,线程ID:%ld\n",ExitCode2,ThreadId2);
 printf("线程3的退出码:%ld,线程ID:%ld\n",ExitCode3,ThreadId3);
 printf("线程4的退出码:%ld,线程ID:%ld\n",ExitCode4,ThreadId4);
 printf("线程5的退出码:%ld,线程ID:%ld\n",ExitCode5,ThreadId5);
 printf("线程6的退出码:%ld,线程ID:%ld\n",ExitCode6,ThreadId6);
 
 //关闭与句柄的关联
 MTVERIFY(CloseHandle(hThread6));
 MTVERIFY(CloseHandle(hThread5));
 MTVERIFY(CloseHandle(hThread4));
 MTVERIFY(CloseHandle(hThread3));
 MTVERIFY(CloseHandle(hThread2));
 MTVERIFY(CloseHandle(hThread1));
 //⑥关闭与Event的关联
 MTVERIFY(CloseHandle(Auto_hEvent));
 MTVERIFY(CloseHandle(Manual_hEvent));

 return 0;
}

DWORD WINAPI ThreadFunc1(LPVOID n)//线程函数1的实现
{
 //④等待Event激发
 //等待激发的Event<事件>对象
 WaitForSingleObject(Auto_hEvent,INFINITE);

 printf("线程%ld正在运行\n",(int)n);

 //⑤手动设置Event为激发
 //激发的一个线程会自动设置为非激发状态
 //若想让其他等待这个事件对象的线程能继续执行
 //需要先把这个事件对象设置激发状态
 SetEvent(Auto_hEvent); //设置为激发状态

 return (DWORD)n;
}

DWORD WINAPI ThreadFunc2(LPVOID n)//线程函数2的实现
{
 //等待激发的Event<事件>对象
 WaitForSingleObject(Manual_hEvent,INFINITE);
 printf("线程%ld正在运行\n",(int)n);

 //激发的一个线程不会自动设置为非激发状态
 //必须手动通过函数来设置其非激发状态
 //这个事件对象设置为非激发状态后,并没有设置为激发状态
 //所以线程 4,5,6只可能会有一个线程能获得这个事件的激发
 //状态并执行下去
 ResetEvent(Manual_hEvent);
 return (DWORD)n;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值