信号量(semaphore)是操作系统用来解决并发中的互斥和同步问题的一种方法。与互斥量不同的地方是,它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。
信号量的工作原理以一个停车场为例,假设停车场只有三个车位,那么同一时刻最多只能有三辆车进入,还有其他车来时则必须在入口等待。只有当有一辆车离开停车场,才能允许其他车辆进入,如此往复。这个停车系统中,每辆车就好比一个线程,空车位数量就好比一个信号量,空车位数量限制了可以活动的线程。假如里面依然是三个车位,但是现在改变了规则,要求每次只能停两辆车,那么一开始进入两辆车,后面得等到有车离开才能有车进入,但是得保证最多停两辆车。对于Semaphore而言,就如同一个空车位数量,限制了可活动的线程数。
信号量的规则如下:
(1)如果当前资源计数大于0,那么信号量处于触发状态(有信号状态),表示有可用资源。
(2)如果当前资源计数等于0,那么信号量属于未触发状态(无信号状态),表示没有可用资源。
(3)系统绝对不会让当前资源计数变为负数
(4)当前资源计数绝对不会大于最大资源计数
- HANDLE WINAPI
- CreateSemaphoreW(
- _In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // Null 安全属性
- _In_ LONG lInitialCount, //初始化时,共有多少个资源是可以用的。 0:未触发状//态(无信号状态),表示没有可用资源
- _In_ LONG lMaximumCount, //能够处理的最大的资源数量 3
- _In_opt_ LPCWSTR lpName //NULL 信号量的名称
- );
- ReleaseSemaphore(
- _In_ HANDLE hSemaphore, //信号量的句柄
- _In_ LONG lReleaseCount, //将lReleaseCount值加到信号量的当前资源计数上面 0-> 1
- _Out_opt_ LPLONG lpPreviousCount //当前资源计数的原始值
- );
-
- CloseHandle(
- _In_ _Post_ptr_invalid_ HANDLE hObject
- );
下面是一个简单程序示例:
- #include
- #include
- #include
- using namespace std;
-
- int main() {
- HANDLE semaphore;
-
- semaphore = CreateSemaphore(NULL, 0, 1, NULL);
-
- CloseHandle(semaphore);
- return 0;
- }
上面这个程序创建了一个初始时0个资源,最大资源数为1的信号量。必须等待ReleaseSemaphore增加信号量后才能被使用。这种最大资源为1的信号量相当于一种特殊的互斥信号量。
下面这段程序创建了两个信号资源,其最大资源都为1;一个初始资源为0,另一个初始资源为1。线程中的for循环每执行一次会将另一个要申请的信号资源的可用资源数+1。因此程序的执行结果为两个线程中的for循环交替执行。
- #include
- #include
- #include
- using namespace std;
-
- static HANDLE semOne;
- static HANDLE semTwo;
- static int num;
-
- /*
- * 信号资源semOne初始为0,最大1个资源可用
- * 信号资源semTwo初始为1,最大1个资源可用
- */
-
- unsigned WINAPI Read(void* arg) {
- int i;
- for (i = 0; i < 5; i++) {
- fputs("Input num:\n", stdout);
- printf("begin read\n");
- WaitForSingleObject(semTwo, INFINITE);
- printf("beginning read\n");
- scanf("%d", &num);
- ReleaseSemaphore(semOne, 1, NULL);
- }
- return 0;
- }
-
- unsigned WINAPI Accu(void* arg) {
- int sum = 0, i;
- for (i = 0; i < 5; ++i) {
- printf("begin Accu\n");
- WaitForSingleObject(semOne, INFINITE);
- printf("beginning Accu\n");
- sum += num;
- printf("sum=%d\n", sum);
- ReleaseSemaphore(semTwo, 1, NULL);
- }
- return 0;
- }
-
- int main() {
- HANDLE hThread1, hThread2;
- semOne = CreateSemaphore(NULL, 0, 1, NULL);//初始值没有可用资源
- semTwo = CreateSemaphore(NULL, 1, 1, NULL);//初始值有一个可用资源
-
-
- hThread1 = (HANDLE)_beginthreadex(NULL, 0, Read, NULL, 0, NULL);
- hThread2 = (HANDLE)_beginthreadex(NULL, 0, Accu, NULL, 0, NULL);
- WaitForSingleObject(hThread1, INFINITE);
- WaitForSingleObject(hThread2, INFINITE);
-
- CloseHandle(semOne);
- CloseHandle(semTwo);
- system("pause");
- return 0;
- }
运行结果