(四) 信号量
1. 内核为每个信号量集合设置了一个semid_ds结构:
struct demid_ds{
struct ipc_perm sem_perm;
unsigned short sem_nsems; //信号量的个数
time_t sem_otime; //上一次semop的时间
time_t sem_ctime;//上一次change的时间
。
。
};
2#include<sys/sem.h>. int semget(key_t key, int nsems, int flag);//创建信号量
成功返回一个对应于信号量集标识符的非负整数,不成功返回-1并设置errno,错误码:
EACCES 存在key的信号量,但没有授予权限
EEXIST 存在key的信号量,但是
( (semflg & IPC_CREATE) && (semflg & IPC_EXCL) ) != 0
EINVAL nsems <= 0或者大于系统的限制,或者nsems与信号量集的大小不符
ENOENT 不存在key的信号量,而且(semflg & IPC_CTEATE) == 0
ENOSPC 要超出系统范围内对信号量的限制了
功能:
函数返回与参数key相关的信号量集标识符。
如果键值为IPC_PRIVATE,或者semflg&IPC_CREAT非零且没有信号量集或标识符关联于key,那么函数就创建标识符及与之相关的信号量集。
参数nsems指定了集合中信号量元素的个数,可用0到nsems-1的整数来引用信号量集合中的单个信号量元素。
参数semflg指定信号量集的优先级,权限的设置与文件权限设置相同,并可以通过semclt来修改权限值,在使用信号量元素之前,应该用semctl对其进行初始化。
注意:
函数如果试图创建一个已经存在的信号量集,如果semflg值中包含了IPC_CREAT和IPC_EXCL,则失败并设置errno为EEXIST;否则返回一个已经存在的信号量集的句柄。
3.int semctl(int semid, int semnum, int cmd, …);//信号量控制
如果成功返回一个非负的值,具体返回值取决于cmd的值。
cmd值GETVAL、GETPID、GETNCNT和GETZCNT使semctl返回与cmd相关的值。
如果成功,所有其它的cmd返回0。
如果不成功semctl返回-1并设置errno,必须检测的错误码:
EACCES 对调用程序来说,操作被否定
EINVAL semid的值或cmd的值无效,或者semnum的值为负或者太大
EPERM cmd的值为IPC_RMID或IPC_SET,且调用程序没有所要求的特权
ERANGE cmd为SETVAL或SETALL,而且要设置的值越界了
功能:
函数semctl为信号量集semid的semnum个元素提供了控制操作。参数cmd指定了操作类型,第四个参数arg可选,是否使用取决于cmd的值。
cmd的值:
GETALL 在arg.array中返回信号量集的值
GETVAL 返回一个特定信号量元素的值
GETPID 返回最后一个操纵元素的进程的进程ID
GETNCNT 返回等待元素增加的进程的个数
GETZCNT 返回等待元素变成零的进程的个数
IPC_RMID 删除semid标识的信号量集
IPC_SET 设置来之arg.buf的信号量集的权限
IPC_STAT 将信号量集semid的semid_ds结构成员拷贝到arg.buf中
SETALL 用arg.array来设置信号量集的值
SETVAL 将一个特定的信号量元素的值设定为arg.val
其中有几个命令需要一个arg参数来读取或存储结构
参数arg的类型为union semun,必须要定义这个类型的数据:
union semum
{
int val
struct semid_ds *buf;
unsigned short *array;
}arg;
4. int semop(int semid, struct sembuf *sops, size_t nsops);//信号量的操作
成功返回0,不成功返回-1并设置errno,必须检测的错误码:
E2BIG nsops的值太大
EACCES 对调用程序来说,操作被否定
EAGAIN 操作会阻塞进程但是(sem_flg&IPC_NOWAIT)!= 0
EFBIG 某一个sops条目的sem_num值小于0,或大于信号量集中元素的数目
EIDRM 信号量集标识符semid已经从系统中删除了
EINTR semop被信号中断
EINVAL semid的值无效,或者请求做SEM_UNDO操作的独立信号量集的数量
超出了限制
ENOSPC 已经超出了对请求SEM_UNDO的进程数的限制
ERANGE 操作会造成semval或semadj值得溢出
功能:
semop函数在单个信号量集上原子的执行sops数组中指定的所有操作。如果其中任何一个单独的元素操作会使进程阻塞,进程就会阻塞而不会执行任何操作。
说明:
结构struct sembuf指定了一个信号量元素操作,包含下列成员。
short sem_num 信号量元素的数量(信号量元素在信号量集中的序号)
short sem_op 要执行的特定元素操作
short sem_flg 为操作指定选项的标志符
sem_op如果是大于零的整数,semop就将这个值与sem_num号信号量元素相加,并唤醒所有等待该元素增加的进程。
如果为零,且信号量元素值不为0,semop就会阻塞调用进程(进程在等待0),并增加等待那个信号量元素值变为零的进程计数。
如果sem_op为负数,那么,如果结果不能为负的话,semop就将sem_op值添加到相应的信号量元素值上去。如果操作可能会使元素值为负,semop就将进程阻塞在使信号量元素值增加的事件上。如果结果值为0,那么semop就唤醒等待0的进程。