在windows中线程间同步的方式有多种包括创建事件对象,互斥对象,临界区等
一,创建事件对象
事件对象也属于内核对象,包含一个使用计数,一个用于指明该事件是一个自动重置的事件还是一个人工重置的事件的布尔值,另一个用于指明该事件处于已通知状态还是未通知状态的布尔值。
有两种不同类型的事件对象。一种是人工重置的事件,另一种是自动重置的事件。当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。
CreateEvent()
函数功能描述
创建或打开一个命名的或无名的 事件对象函数原型:
HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, // 安全属性 BOOL bManualReset, // 复位方式 BOOL bInitialState, // 初始状态 LPCTSTR lpName // 对象名称 );参数:
lpEventAttributes:
返回值
如果函数调用成功,函数返回事件对象的句柄。如果对于命名的对象,在函数调用前已经被创建,函数将返回存在的事件对象的句柄,而且在GetLastError函数中返回ERROR_ALREADY_EXISTS。 如果函数失败,函数返回值为NULL,如果需要获得详细的错误信息,需要调用GetLastError。注备: 当该事件为手动复原时,一旦该事件对象为有信号状态,所有等待该事件对象的线程均变为可调度线程,直到手工调用ResetEvent(HANDLE)该事件对象才变为无信号状态; 当该事件为自动复原时,一旦该事件对象为有信号状态,所有等待该事件对象的线程中只有一个线程(A)为可调度线程,并且一旦A请求到事件对象系统立马将事件对象设置为无信号状态。
用SetEvent(HANDLE)可将事件对象设置为有信号状态。
例如:
HANDLE g_xEvent = CreateEvent(NULL , FALSE , FALSE , NULL);
SetEvent(g_xEvent);
waitforsingleobject(handle , INFINITE);
.
.
被保护的代码段
SetEvent(g_xEvent);
二. 创建互斥对象
互斥对象(mutex)属于内核对象,它能够确保线程拥有对单个资源的互斥访问权。互斥对象包含一个使用数量,一个线程ID和一个计数器。ID用于标识系统中的哪个线程当前拥有互斥对象,计数器用于指明该线程拥有互斥对象的次数。没有线程拥有互斥对象时其处于有信号状态,否则其处于无信号状态。
CreateMutex();
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes , // 指向安全属性的指针 BOOL bInitialOwner , // 初始化互斥对象的所有者 LPCTSTR lpName // 指向互斥对象名的指针 );创建一个有名或无名的互斥对象; lpMutexAttributes为NULL时互斥对象为默认安全属性,不能被子进程继承;bInitialOwner为true时调用线程拥有互斥对象,互斥对象处于无信号状态,为false时没有线程拥有互斥对象,互斥对象处于有信号状态,其线程ID为0;lpName为NULL时为匿名互斥对象。
返回值:返回互斥对象的句柄
例如:
HANDLE handle = createmutex(null , false , null);
waitforsingleobject(handle ,INFINITE); 申请互斥对象,得到互斥对象后才能返回,否则一直等待,得到互斥对象后互斥对象变为无信号状态
.
.
被保护的代码段
ReleaseMutex(handle); 将互斥对象的线程ID设为0,释放互斥对象,变为有信号状态
当createmutex(),waitforsingleobject()处于同一个线程即互斥对象的线程ID与申请互斥对象的线程ID相同时,这时(互斥对象无信号)waitforsingleobject()也能成功,互斥对象的计数器变为2.
三,创建临界区
1.CRITICAL_SECTION c_st; //设置临界区对象
2. void InitializeCriticalSection(&c_st); //初始化临界区对象
3.void EnterCriticalSection(&c_st) ; // 判断是否可拥有临界区所有权,若可拥有,则进入(EnterCriticalSection(&c_st)立即返回) ,否则线程等待(EnterCriticalSection(&c_st)不立即返回)。
4.void LeaveCriticalSection(&c_st); //释放临界区对象
5.DeleteCriticalSection(&c_st); //当不再需要临界区对象时释放临界区对象所拥有的资源