临界区:只能实现子进程之间的同步,即控制子进程之间访问资源的互斥性,无法实现父线程和子线程之间的同步
事件:不仅可以实现子进程之间的同步,也可以实现父子进程之间的同步
示例一:使用手动重置事件实现父子进程之间的同步,使用临界区实现子进程之间的同步(即互斥)
该示例要同步两种数据,一种是全局资源g_count,另一种是父子线程之间的传递数据i,前者有事件完成,后者有临界区完成
#include <iostream>
#include <Windows.h>
using namespace std;
int g_count = 0;// 全局资源(由临界区控制子线程对该资源的访问)
HANDLE hEvent = NULL;
CRITICAL_SECTION g_cs;
DWORD WINAPI ThreadProc(PVOID pParam)
{
int nThreadNum = *(int *)pParam;
SetEvent(hEvent);// 使事件处于触发状态,此时父线程会被唤醒并准备执行
// 注意Sleep的作用:让当前子线程等待一会,使cpu切换到主线程执行
Sleep(50);
EnterCriticalSection(&g_cs);
++g_count;
cout << "线程编号为" << nThreadNum << " 全局资源为" << g_count << endl;
LeaveCriticalSection(&g_cs);
return 0;
}
int main(int argc, char *argv[])
{
hEvent = CreateEvent(0,TRUE,FALSE,0);
InitializeCriticalSection(&g_cs);
HANDLE hThreads[10];
for (int i = 0 ; i < 10 ; ++i)
{
// i用来标示每一个子线程,i由父线程传递给子线程,因此要控制父子线程之间i的同步(由事件内核对象控制),否则同一个i值可能标示多个子线程
hThreads[i] = CreateThread(0,0,ThreadProc,&i,0,0);
WaitForSingleObject(hEvent,INFINITE);// 等待hEvent被触发,此时主线程处于等待状态,刚创建的子线程会被唤醒执行
ResetEvent(hEvent);// 将事件设置为未触发状态
}
// 等待所有线程执行完毕后返回
WaitForMultipleObjects(10,hThreads,TRUE,INFINITE);
for (int i = 0 ; i < 10 ; ++i)
{
CloseHandle(hThreads[i]);
}
DeleteCriticalSection(&g_cs);
CloseHandle(hEvent);
return 0;
}