先前介绍的POSIX信号量概念:
- 二值信号量:0,1
- 计数信号量:0和某个限制值之间的信号量。
System V 中信号量:
计数信号量集:一个或多个信号量,其中每个都是计数信号量。
对于系统的每个信号量集,内核维护一个信息结构:<sys/sem.h>中定义
/* Data structure describing a set of semaphores. */
struct semid_ds
{
struct ipc_perm sem_perm; /* operation permission struct */
__time_t sem_otime; /* last semop() time */
__syscall_ulong_t __glibc_reserved1;
__time_t sem_ctime; /* last time changed by semctl() */
__syscall_ulong_t __glibc_reserved2;
__syscall_ulong_t sem_nsems; /* number of semaphores in set */
__syscall_ulong_t __glibc_reserved3;
__syscall_ulong_t __glibc_reserved4;
};
semget、semop、semctl
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
// 返回:若成功返回非负标识符,出错为-1
int semop(int semid, struct sembuf *sops, size_t nsops);
// 返回:若成功返回0,出错为-1
int semtimedop(int semid, struct sembuf *sops, size_t nsops, const struct timespec *timeout);
int semctl(int semid, int semnum, int cmd, ...);
// 返回:成功返回非负值,出错-1
semget 函数:创建一个信号量集,或者访问一个已存在的信号量集。
- 返回值:一个称为信号量标识符的整数。
- nsems参数:指定集合中的信号量数。若不创建,只访问一个信号量集,可以设置为0。一旦创建,就不能改变其中的信号量数。
- semflg:SEM_R 和SEM_A的组合。R表示read。A表示alter。还可以与IPC_CREAT、IPC_EXCL按位与。
当创建一个信号量集时,semid_ds结构中的以下成员被初始化:
- sem_perm 结构中的uid 和 cuid 成员被置为调用进程的有效用户ID,gid 和 cgid 成员被置为调用进程的有效组ID。
- semflg参数中的读写权限位存入sem_perm.mode。
- sem_otime被置为0,sem_ctime则被置为当前时间。
- sem_nsems被置为nsems参数的值。
- 与该集合中每个信号量关联的各个sem结构并不初始化。这些结构是在以SET_VAL或SETALL命令调用semctl时初始化的。
semop 函数:打开后,对其中一个或者多个信号量的操作。
其中sembuf结构:
/* Structure used for argument to `semop' to describe operations. */
struct sembuf
{
unsigned short int sem_num; /* semaphore number (0,1,...,nsems-1) */
short int sem_op; /* semaphore operation */
short int sem_flg; /* operation flag ( 0, IPC_NOWAIT, SEM_UNDO ) */
};
/* Flags for `semop'. */
#define SEM_UNDO 0x1000 /* undo the operation on exit */
sem_op:正数,0,负数
semctl 函数:对一个信号量执行各种控制操作。
semnum参数:信号量成员。仅仅用于GETVAL、SETVAL、GETNCNT、GETZCNT、GETPID命令。
第四个参数是可选的,取决于第三个参数cmd。
注意:这个联合需要应用自己定义,它是按值传递的,不是按引用传递的。
/* Commands for `semctl'. */
#define GETPID 11 /* get sempid */
#define GETVAL 12 /* get semval */
#define GETALL 13 /* get all semval's */
#define GETNCNT 14 /* get semncnt */
#define GETZCNT 15 /* get semzcnt */
#define SETVAL 16 /* set semval */
#define SETALL 17 /* set all semval's */
/* Control commands for `msgctl', `semctl', and `shmctl'. */
#define IPC_RMID 0 /* Remove identifier. */
#define IPC_SET 1 /* Set `ipc_perm' options. */
#define IPC_STAT 2 /* Get `ipc_perm' options. */
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 (Linux-specific) */
};
struct seminfo
{
int semmap;
int semmni;
int semmns;
int semmnu;
int semmsl;
int semopm;
int semume;
int semusz;
int semvmx;
int semaem;
};
GETVAL ---把semval的当前值作为函数返回值返回。既然信号量绝不会是负数(semval被声明成一个整数unsigned short),那么成功的返回值总是非负数。
SETVAL ---把semval值设置成为arg.val。如果操作成功,那么相应信号量在所有进程中的信号量调整值(semadj)将被置为0。
GETPID ---把sempid的当前值作为函数返回值返回。
GETNCNT---把semncnt的当前值作为函数返回值返回。
GETZCNT---把semzcnt的当前值作为函数返回值返回。
GETALL----返回所指定信号量集内每个成员的semval值。这些值通过arg.array指针返回,函数本身的返回值则为0。注意,调用者必须分配一个unsigned short整数数组,该数组要足够容纳所指定信号量集内所有成员的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参数指向的结构中的相应成员。semid_ds结构中的sem_ctime成员也被设置成当前时间。
IPC_STAT--(通过arg.buf参数)返回所指定信号量集当前的semid_ds结构。注意,调用者必须首先分配一个semid_ds结构,并把arg.buf设置成指向这个结构。
信号量限制: