以一个停车场的运作为例。简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆直接进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入外面的一辆进去,如果又离开两辆,则又可以放入两辆,如此往复。
在这个停车场系统中,车位是公共资源,每辆车好比一个线程,看门人起的就是信号量的作用。
抽象的来讲,信号量的特性如下:信号量是一个非负整数(车位数),所有通过它的线程/进程(车辆)都会将该整数减一(通过它当然是为了使用资源),当该整数值为零时,所有试图通过它的线程都将处于等待状态。在信号量上我们定义两种操作: Wait(等待) 和 Release(释放)。当一个线程调用Wait操作时,它要么得到资源然后将信号量减一,要么一直等下去(指放入阻塞队列),直到信号量大于等于一时。Release(释放)实际上是在信号量上执行加操作,对应于车辆离开停车场,该操作之所以叫做“释放”是因为释放了由信号量守护的资源。
可以用信号量实现主线程与子线程间的同步,而用关键段实现子进程间的互斥:
第一个 CreateSemaphore
函数功能:创建信号量
函数原型:
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
LONG lInitialCount,
LONG lMaximumCount,
LPCTSTR lpName
);
函数说明:
第一个参数表示安全控制,一般直接传入NULL。
第二个参数表示初始资源数量。
第三个参数表示最大并发数量。
第四个参数表示信号量的名称,传入NULL表示匿名信号量。
第二个 OpenSemaphore
函数功能:打开信号量
函数原型:
HANDLE OpenSemaphore(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName
);
函数说明:
第一个参数表示访问权限,对一般传入SEMAPHORE_ALL_ACCESS。详细解释可以查看MSDN文档。
第二个参数表示信号量句柄继承性,一般传入TRUE即可。
第三个参数表示名称,不同进程中的各线程可以通过名称来确保它们访问同一个信号量。
第三个 ReleaseSemaphore
函数功能:递增信号量的当前资源计数
函数原型:
BOOL ReleaseSemaphore(
HANDLE hSemaphore,
LONG lReleaseCount,
LPLONG lpPreviousCount
);
函数说明:
第一个参数是信号量的句柄。
第二个参数表示增加个数,必须大于0且不超过最大资源数量。
第三个参数可以用来传出先前的资源计数,设为NULL表示不需要传出。
注意:当前资源数量大于0,表示信号量处于触发,等于0表示资源已经耗尽故信号量处于末触发。在对信号量调用等待函数时,等待函数会检查信号量的当前资源计数,如果大于0(即信号量处于触发状态),减1后返回让调用线程继续执行。一个线程可以多次调用等待函数来减小信号量。
最后一个 信号量的清理与销毁
由于信号量是内核对象,因此使用CloseHandle()就可以完成清理与销毁了。
#include<stdio.h> #include<process.h> #include<windows.h> volatile long g_nLoginCount; const int THREAD_NUM = 10; volatile long g_num; CRITICAL_SECTION g_thread; HANDLE g_Semaphore; //信号量 unsigned int __stdcall ThreadFun(void *pPM){ int thread_id=*((int *)pPM); ReleaseSemaphore(g_Semaphore,1,NULL);//信号量++ Sleep(50); EnterCriticalSection(&g_thread); g_num++; Sleep(0); printf("ID : %d 全局:%d ",thread_id,g_num); LeaveCriticalSection(&g_thread); return 0; } int main(){ InitializeCriticalSection(&g_thread); g_Semaphore = CreateSemaphore(NULL,0,1,NULL);//当前0个资源,最大允许1个同时访 g_nLoginCount = 0; g_num=0; HANDLE handle[THREAD_NUM]; int num=20; g_nLoginCount = 0; for(int i = 0;i < THREAD_NUM; i++){ handle[i] = (HANDLE)_beginthreadex(NULL,0,ThreadFun,&i,0,NULL); WaitForSingleObject(g_Semaphore,INFINITE); } WaitForMultipleObjects(THREAD_NUM,handle,TRUE,INFINITE); CloseHandle(g_Semaphore); DeleteCriticalSection(&g_thread); return 0; }
总结:信号量与事件的区别在与,信号量的大小可以设置,而事件可以看做是“大小为1的信号量”。
参考:http://blog.csdn.net/morewindows/article/details/7481609