信号量概述
信号量与已经介绍过的IPC结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据
特点:
- 信号量用于进程间同步,若要在进程间传递数据需要结合共享内存
- 信号量基于操作系统的P操作和V操作,程序对信号量的操作都是原子操作
- 每次对信号量的PV操作不仅限于对信号量值加1或减1,而且可以加减任意正整数
- 支持信号量组
临界资源:多道程序系统中存在许多进程,它们共享各种资源,如:共享内存,然而有很多资源一次只能供一个进程使用,一次仅允许一个进程使用的资源称为临界资源。许多物理设备都属于临界资源,如:输入机,打印机,磁带机等
信号量相关的api
最简单的信号量是只能取0和1的变量,这也是信号量最常见的一种形式,叫做二值信号量。而可以取多个正整数的信号量被称为通用信号量。
Linux下的信号量函数都是在通用的信号量数组上进行操作,而不是在一个单一的二值信号量上进行操作
1.int semget(key_t key, int num_sems, int sem_flags);
功能:创建或获取一个信号量组
返回值:成功返回信号量集ID,失败返回-1
参数说明:
- key:有两种情况:1)0(IPC_PRIVATE):会建立新信号量集对象;2)大于0的32位整数:视参数sem_flags来确定操作,通常要求此值来源于ftok函数返回的IPC键值
- num_sems:创建信号量集中信号量的个数,该参数只在创建信号量集时有效
- sem_flags:有三种情况:1)0:取信号量集标识符,若不存在则函数会报错;2)IPC_CREAT:当sem_flags & IPC_CREAT 为真时,如果内核中不存在键值与key相等的信号量集,则新建一个信号量集;如果存在这样的信号量集,返回此信号量集的标识符;3)IPC_CREAT | IPC_EXCL:如果内核中不存在键值与key相等的信号量集,则新建一个消息队列;如果存在,则报错
补充:上述sem_flags参数为模式标志参数,使用时需要与IPC对象存取权限(如0666)进行 | 运算来确定信号量集的存取权限
2.int semctl(int semid, int sem_num, int cmd, union semun arg);
功能:控制信号量的相关信息
返回值:成功返回一个大于或等于0,失败返回-1
参数说明:
-
semid:信号量集ID
-
sem_num:信号量集数组上的下标,表示一个信号量
-
cmd:有如下设置方法
IPC_STAT :从信号量集上检索semid_ds结构并存到semun联合体参数的成员buf的地址中
IPC_SET:设置一个信号量集合的semid_ds结构中ipc_perm域的值,并从semun的buf中取出值
IPC_RMID:从内核中删除信号量集合
GETALL:从信号量集合中获得所有信号量的值,并把其整数值存到semun联合体成员的一个指针数组中
GETNCNT:返回当前等待资源的进程个数
GETPID:返回最后一个执行系统调用semop()进程的PID
GETVAL:返回信号量集合内单个信号量的值
GETZCNT:返回当前等待100%资源利用的进程个数
SETALL:与GETALL正好相反
SETVAL:用联合体中val成员的值设置信号量集合中单个信号量的值 -
第四个参数是一个联合体
union semun { int val; // SETVAL用的值 struct semid_ds *buf; // IPC_STAT和IPC_SET用的semid_ds结构 unsigned short