说到底,信号量就是用来控制多个进程对共享资源使用的一个计数器
相关数据结构
1、sem
信号量对象是多个信号量的集合,而这个集合在linux中是以数组的形式实现的,数组的每个成员都是一个单独的信号量,即sem结构
struct
{
short sempid; /*最近一次操作信号量的进程的id*/
unsigned short semval; /*信号量的计数值*/
unsigned short semncnt; /*等待使用资源的进程数目*/
unsigned short semzcnt; /*等待资源完全空闲的进程数目*/
}
2、semun
union semun
{
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
unsigned short *array; /* array for GETALL & SETALL */
struct seminfo *__buf; /* buffer for IPC_INFO */
void *__pad;
};
3、sembuf
被用来定义对信号量对象的基本操作
struct sembuf
{
unsigned short sem_num; /* 接受操作的信号量在信号量数组中的序号,即数组下标 */
short sem_op; /* 定义了进行的操作,取值正、0和负值 */
short sem_flg; /* 控制操作行为的标志 */
};
-
如果
sem_op
值为负,就从指定的信号量中减去相应的值,对应着获取信号量所监控的资源的操作。若sem_flg
中没有指定IPC_NOWAIT
标志,如果现有的信号量数值小于sem_op
的绝对值(表示现有资源少于所需资源),调用semop()
的进程就会阻塞直到信号量的数值大于sem_op
的绝对值(表示有足够的资源)。 -
如果
sem_op
值为正,就在指定的信号量中加上相应的值,这对应着释放信号量所监控的资源的操作。 -
如果
sem_op
值为零,调用semop()
的进程会被阻塞直到对应的信号量值为0。这操作就是等待信号量所监控的资源被全部使用。利用这个操作可以动态监控资源的使用并调整资源的分配,避免不必要的等待。
4、semid_ds
struct semid_ds
{
struct ipc_perm sem_perm; /* permissions .. see ipc.h */
__kernel_time_t sem_otime; /* 最近一次semop操作的时间 */
__kernel_time_t sem_ctime; /* 信号量对象最近一次改动发生的时间 */
struct sem *sem_base; /* 信号里数组的起始地址 */
struct sem_queue *sem_pending; /* 指向还未进行的操作 */
struct sem_queue **sem_pending_last; /* 指向最后一个还未进行的操作 */
struct sem_undo *undo; /* undo requests on this array */
unsigned short sem_nsems; /* 信号量数组成员数目 */
};
和msqid_ds
类似,semid_ds
用来储存每个信号量对象的有关信息。
相关函数
1、semget()
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
semget
建立新的信号量对象或者获取已有对象的标识符。参数semflg
与消息队列中的msgflg
参数取值一样。参数nsems
是信息量对象中信号量的数目,也就是信号量数组成员的个数。/usr/include/linux/sem.h
中定义了它的上限
#define SEMMSL 250
2、semop()
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, unsigned nsops);
semop()
用来改变信号量对象中各个信号量的状态。参数sops
是sembuf
类型的数组,定义了semop()
函数所要进行的操作序列;参数nsops
是sops
数组的长度也就是semop()
进行的操作个数。
3、semctl()
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);
semctl()
直接来控制信号量对象。semid
为信号量对象标识符,semnum
信号量在集合中的序号。根据cmd
的取值,可带第4个参数,union semun arg
。cmd
可取如下值
IPC_STAT
: 取得semid
的semid_ds
信息,并存放在arg
的buf
中IPC_SET
: 用arg
中的buf
设定信号量对象的semid_ds
结构IPC_RMID
: 删除信号量对象GETALL
: 取得信号量对象所有信号量的值,并存放在arg
的array
中返回GETNCNT
: 返回正在等待使用某个信号量所控制的资源的进程数目GETPID
: 返回最近一个对某个信号量调用semop()
的进程的pid
GETVAL
: 返回集合中最后一个信号量的semval
值GETZCNT
: 返回正在等待某个信号量所控制资源被全部使用的进程数目SETALL
:用arg
中array
来设定对象内处个信号量的值SETVAL
: 用arg
中val
的值来设定对象中某个信号量的值