21-线程同步:信号量

线程同步:信号量

1.内核对象的状态

  • 触发状态(有信号状态),表示有可用资源。

  • 未触发状态(无信号状态),表示没有可用资源

2.信号量

用于保证某个内核对象的引用不超过某个最大值。

组成:

  • 计数器:该内核对象被使用的次数

  • 最大资源数量:标识信号量能控制的最大资源数量(实际上可能没有那么多资源)

  • 当前资源数量:表示当前开放资源的个数(资源可以不被线程占用,但是也没开放)

使用规则:

  • 当前资源数量>0:说明有可用资源,信号量处于触发状态

  • 当前资源数量=0:说明无可用资源,信号量处于未触发状态

补充:

信号量与互斥量不同的地方是,它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。信号量对象对线程的同步方式与前面几种方法不同,信号允许多个线程同时使用共享资源。

3.创建信号量CreateSemaphoreW函数

创建一个信号量,并指定该信号量的初始值和最大值

参数:

  • lpSemaphoreAttributes:安全属性,一般用NULL

  • lInitialCount:初始化时,有多少个资源可用

  • lMaximumCount:最大可控制的资源数量

  • lpName:信号的名称,一般用NULL匿名

返回:

  • 信号句柄

4.增加信号量ReleaseSemaphore函数

  • hSemaphore:信号量的句柄

  • lReleaseCount:增加的资源计数值(如果是n,则加n)

  • lpPreviousCount:当前资源计数的原始值

案例

#include <stdio.h>
#include <windows.h>
#include <process.h>
unsigned WINAPI Read(void* arg);
unsigned WINAPI Accu(void* arg);
static HANDLE semOne;
static HANDLE semTwo;
static int num;
int main(int argc, char* argv[])
{
HANDLE hThread1, hThread2;
semOne = CreateSemaphore(NULL, 0, 1, NULL);
//semOne 没有可用资源 只能表示0或者1的二进制信号量 无信号
semTwo = CreateSemaphore(NULL, 1, 1, NULL);
//semTwo 有可用资源,有信号状态 有信号
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;
}
unsigned WINAPI Read(void* arg)
{
int i;
for (i = 0; i < 5; i++)
{
fputs("Input num: ", stdout); // 1 5 11
printf("begin read\n"); // 3 6 12
//等待内核对象semTwo的信号,如果有信号,继续执行;如果没有信号,等待
WaitForSingleObject(semTwo, INFINITE);
printf("beginning read\n"); //4 10 16
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"); //2 9 15
//等待内核对象semOne的信号,如果有信号,继续执行;如果没有信号,等待
WaitForSingleObject(semOne, INFINITE);
printf("beginning Accu\n"); //7 13
sum += num;
printf("sum = %d \n", sum); // 8 14
ReleaseSemaphore(semTwo, 1, NULL);
}
printf("Result: %d \n", sum);
return 0;
}