System V 信号量
在提到Posix 信号量时,指的是二值信号量或计数信号量,而System V信号量指的是入了计数信号量集
二值信号量:其值为0或1,类似于互斥锁,资源被锁住时为0,资源可用为1
计数信号量:其值在0和某个限制值之间的信号量,信号量的值就是可用资源数
计数信号量集:一个或多个信号量构成一个集合,集合中每个元素都是计数信号量(每个集合的信号量数存在一个限制)
semid_ds结构:
内核为每个信号量集维护的信息结构
#include <sys/sem.h> struct semid_ds{ struct ipc_perm sem_perm; // 当前信号量的访问权限 struct sem *sem_base; // 内核用于维护某个给定信号量的一组值的内部数据结构 ushort sem_nsems; // 集合中信号量的数目 time_t sem_otime; // 最近一次执行semop()的时间 time_t sem_ctime; // 集合创建时间或最近一次IPC_SET的时间 }; struct sem{ ushort_t semval; // 信号量实际值 short sempid; // 对信号量值执行最后一次操作的进程的进程ID ushort_t semncnt; // 等待信号量值增长的进程数 ushort_t semzcnt; // 等待信号量值变为0的进程数 };
semget()函数:
#include <sys/sem.h> // 创建一个信号量集或访问一个已存在的信号量集 // 成功返回非负信号量标识符,出错返回-1 int semget(key_t key, int nsems, int oflag); // key: IPC 键 // nsems:指定集合中信号量数 // oflag:SEM_R(读)和SEM_A(改)的组合,还可以按位与IPC_CREAT或IPC_CREAT|IPC_EXCL
semop()函数:
#include <sys/sem.h> // 对信号量集中一个或多个信号量进行操作 // 成功返回0,出错返回-1 int semop(int semid, struct sembuf *opsptr, size_t nops); // semid:由semget()函数返回的信号量标识符 // nops: 指出opsptr指向的结构数组的元素数量 // opsptr:指向一个如下的数组 struct sembuf{ short sem_num; // 信号量集中信号量的索引值:0, 1, ... , nsems-1(sem_base[sem_num], 指定对某个特定信号量进行操作) short sem_op; // 指定对特定信号量的操作 short sem_flg; // 操作标志,0, IPC_NOWAIT、SEM_UNDO }; // sembuf结构内元素的排列顺序并不保证如上述那样,只保证该结构中有上述三个元素 // sembuf结构不能静态初始化(struct sembuf value = {0, 0, 0} // Error) // sembuf结构需要运行时初始化(struct sembuf value; value.sem_num = 0; ...) // sem_op:每个特定的操作有sem_op确定,它可以是负数、0、正数 // sem_op为正数时,其值加到semval(信号量当前值)上,对应于释放信号量控制的资源 // 如果指定了SEM_UNDO标志,就从相应信号量的semadj(所指定信号量针对调用进程的调整值)减去sem_op // sem_op为0,调用者等待semval变为0,如果semval已经为0,则立即返回 // sem_op为负数,调用者希望等待semval变为大于或等于sem_op的绝对值,这对应于分配资源
semctl()函数:
#include <sys/sem.h> // 对一个信号量执行各种控制操作 // 成功返回非负值,出错返回-1 int semctl(int semid, int semnum, int cmd, ... /* union semun arg */); // semid: 标识其操作待控制的信号量集 // semnum: 标识信号量集内的某个成员(sem_base[sem_num]) // cmd:可选值如下(除非另外说明,操作成功函数返回值为0,出错为-1) // GETVAL:将semval的当前值作为函数返回值返回 // SETVAL:将semval设为arg.val(若操作成功,那么相应信号量的semadj被设为0) // GETPID:将sempid的当前值作为函数返回值返回 // GETNCNT:将semncnt(等待semval变为大于其当前值的线程数)的当前值作为函数返回值返回 // GETZCNT:将semzcnt(等待semval变为0的线程数)的当前值作为函数返回值返回 // GETALL:返回指定信号量集内每个成员的semval值(这些值通过arg.array指针返回) // SETALL:设置指定信号量集内每个成员的semval值(这些值通过arg.array指针传递) // IPC_RMID:将由semid指定的信号量集从系统删除 // IPC_SET:设置指定信号量集的semid_ds结构中的sem_perm.uid、sem_perm.gid、sem_perm.mode,这些值由arg.buf参数指向的结构中的相应成员指定 // IPC_STAT:返回指定信号量集当前的semid_ds结构(通过arg.buf) // arg: 可选参数,根据 cmd 参数而定 union semun{ int val; struct semid_ds *buf; ushort *array; };