同步对象
/************************************************************************/
/* 同步对象(Mutex)
互斥对象具有的机制:如果互斥对象没有被任何线程拥有,那么它是"标记的",如果被一个线程所拥有,那么它是"未标志的";任何一个线程获得后,互斥对象就是"未标志的",
其他线程不可以再拥有这个互斥对象。同一时刻,一个互斥对象最多只能被一个线程拥有,从而实现"互斥"。
概览
同一时刻只有一个线程可以拥有Mutex对象
全局名称的Mutex可以跨进程使用
在没有线程拥有它时处于通知(置位)状态
被线程拥有的时候处于非通知(非置位)状态
函数
创建一个Mutex同步对象
HANDLE CreateMutex(
__in_opt LPSECURITY_ATTRIBUTES lpMutexAttributes,//不支持,设置为NULL
__in BOOL bInitialOwner, //是否为创建该Mutex的线程所拥有
__in_opt LPCSTR lpName ); //可选,该Mutex的名字
释放对Mutex的占用
BOOL ReleaseMutex( //一个线程释放了互斥对象后,如果其他线程在等待互斥对象置位,则等待的线程可以得到该互斥对象,等待函数返回,互斥对象被新的线程所拥有
__in HANDLE hMutex //Mutex的句柄
);
*/
/************************************************************************/
/************************************************************************/
/* 同步对象(Semaphore)
信号量维护了一个计数器,计数器的值可以在0到指定的最大值之间。
当一个线程完成了对信号量的等待后,信号量计数器值减少;当一个线程释放信号量是,信号量计数器值增加。
当计数器值达到零后,信号量是"未标志的",当计数器值大于零时,信号量是“标志的”。
当计数器值降为到零时,任何线程都无法等待信号量变为“标志的”,因此信号量对限制可访问共享数据的线程数量很有用处。
使用信号量可以达到限制访问共享数据的线程数量的功能。
概览
限制占有共享资源的数量(如果一个Semaphore带有计数n,这表示同时最多可以有n个线程占有该Semaphore)
全局名称的Semaphore可以跨进程使用
引用计数大于0时处于通知状态
引用计数小于等于0时处于非通知状态
函数
创建一个Semaphore对象
HANDLE WINAPI CreateSemaphore(
__in_opt LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, //不支持,设为NULL
__in LONG lInitialCount, //初始计数值
__in LONG lMaximumCount, //最大支持的线程数,最大计数值
__in_opt LPCWSTR lpName ) //可选,semaphore的名字
释放Semaphore
BOOL ReleaseSemaphore(
__in HANDLE hSemaphore, //要释放的Semaphore句柄
__in LONG lReleaseCount, //释放的引用个数,可以一次释放多个计数
__out_opt LPLONG lpPreviousCount ) //返回释放前的semaphore计数
*/
/************************************************************************/
/************************************************************************/
/* 同步对象(Event)
概览
全局名称的Event可以跨进程使用
事件发生时处于通知状态
事件未发生时处于非通知状态
函数
创建同步对象Event
HANDLE CreateEvent(
__in_opt LPSECURITY_ATTRIBUTES lpEventAttributes, //不可用,设为NULL
__in BOOL bManualReset, //是否需要人工重置,所谓重置是指将已标记的事件对象再重新设置为未标志。如果为TRUE,
//则需ResetEvent()来重置,如果为FALSE,那么等待函数在等待到事件置位后,自动将事件重置。
__in BOOL bInitialState, //初始状态,TRUE为通知状态
__in_opt LPCWSTR lpName //可选,Event的名字
)
把Event同步对象设置为通知状态/未通知状态
BOOL SetEvent( __in HANDLE hEvent ) //Event的句柄
BOOL ResetEvent( __in HANDLE hEvent )//Event的句柄,将事件重置为"未通知"状态。如果事件时手工重置的,那么需要使用此函数爱重置事件。
*/
/************************************************************************/
/************************************************************************/
/* 同步(CriticalSection)
概览
允许多个线程共享访问同一块数据
使用互斥访问保护数据
其他线程会block直到占用者放弃临界区
每个CriticalSection都是OS提供的一个数据结构,只能在同一个进程内部使用,比Mutex要高效
函数
InitializeCriticalSection( __out LPCRITICAL_SECTION lpCriticalSection ); //分配CriticalSection结构
EnterCriticalSection( __inout LPCRITICAL_SECTION lpCriticalSection ); //在占有CriticalSection的线程调用LeaveCriticalSection之前会阻塞
TryEnterCriticalSection( __inout LPCRITICAL_SECTION lpCriticalSection );//EnterCriticalSection的非阻塞版
LeaveCriticalSection( __inout LPCRITICAL_SECTION lpCriticalSection ); //释放CriticalSection的所有权
DeleteCriticalSection( __inout LPCRITICAL_SECTION lpCriticalSection ); //释放InitializeCriticalSection分配的资源
*/
/************************************************************************/
Mutex实例
//实例 使用Mutex对象对共享的全局变量iData进行访问
#include <windows.h>
#include <stdio.h>
HANDLE hMutex;
int iData=0;
DWORD WINAPI ThreadProc1(LPVOID lParam)
{
WaitForSingleObject(hMutex,INFINITE); //获取Mutex对象
for (int i=0;i<(int)lParam;i++)
{
iData++; //访问共享资源
printf("iData++ %d\n",iData);
}
ReleaseMutex(hMutex); //释放同步对象
return 0;
}
DWORD WINAPI ThreadProc2(LPVOID lParam)
{
WaitForSingleObject(hMutex,INFINITE); //获取Mutex对象
for (int i=0;i<(int)lParam;i++)
{
iData--; //访问共享资源
printf("iData-- %d\n",iData);
}
ReleaseMutex(hMutex); //释放同步对象
return 0;
}
void Init()
{
hMutex=CreateMutex(NULL,FALSE,NULL);
CreateThread(NULL,0,ThreadProc1,(LPVOID)4,0,NULL);
CreateThread(NULL,NULL,ThreadProc2,(LPVOID)5,NULL,NULL);
}
int main()
{
Init();
system("pause");
return 0;
}
Event实例
//实例 使用Event对象对共享的全局变量进行访问
#include <windows.h>
#include <stdio.h>
HANDLE hEvent;
int iData=0;
DWORD WINAPI ThreadProc1(LPVOID lParam)
{
WaitForSingleObject(hEvent,INFINITE); //等待事件发生
for (int i=0;i<(int)lParam;i++)
{
iData++; //访问共享资源
printf("iData++ %d\n",iData);
}
SetEvent(hEvent); //让事件再次发生
return 0;
}
DWORD WINAPI ThreadProc2(LPVOID lParam)
{
WaitForSingleObject(hEvent,INFINITE); //等待事件发生
for (int i=0;i<(int)lParam;i++)
{
iData--; //访问共享资源
printf("iData-- %d\n",iData);
}
SetEvent(hEvent); //让事件再次发生
return 0;
}
VOID Init()
{
hEvent=CreateEvent(NULL,FALSE,TRUE,NULL);
CreateThread(NULL,NULL,ThreadProc1,(LPVOID)4,NULL,NULL);
CreateThread(NULL,NULL,ThreadProc2,(LPVOID)5,NULL,NULL);
}
int main()
{
Init();
system("pause");
return 0;
}
CriticalSection实例
//实例 使用CriticalSection对象对共享的全局变量进行访问
#include <windows.h>
#include <stdio.h>
CRITICAL_SECTION cs;
int iData=0;
DWORD WINAPI ThreadProc1(LPVOID lParam)
{
EnterCriticalSection(&cs); //进入临界区
for (int i=0;i<(int)lParam;i++)
{
iData++; //访问共享数据
printf("iData++ %d\n",iData);
}
LeaveCriticalSection(&cs); //离开临界区
return 0;
}
DWORD WINAPI ThreadProc2(LPVOID lParam)
{
EnterCriticalSection(&cs); //进入临界区
for (int i=0;i<(int)lParam;i++)
{
iData--; //访问共享数据
printf("iData-- %d\n",iData);
}
LeaveCriticalSection(&cs); //离开临界区
return 0;
}
void Init()
{
InitializeCriticalSection(&cs);
CreateThread(NULL,NULL,ThreadProc1,(LPVOID)4,NULL,NULL);
CreateThread(NULL,NULL,ThreadProc2,(LPVOID)5,NULL,NULL);
}
int main()
{
Init();
system("pause");
return 0;
}
上面3个实例的结果都是: