在linux下,我们平时所说的信号量,其实是
信号量集的操作,可以同时操作若干信号量。网上这方面的文章相当多,但很多文章对其细节操作都语焉不详。下面,我将信号量集的操作函数进行详细描述。
一、函数
-
/* 创建信号量集 */
-
int semget(key_t key, int nsems, int semflg);
-
return: If
successful, the return value will be the semaphore set identifier (a
non-negative integer), otherwise -1 is returned, with errno indicating
the error.
-
key: 不再描述。
-
nsems: 创建的信号量集里面,信号量的个数。
-
semflg: IPC_CREAT|IPC_EXCL。
-
注意: 1. 对nsems>1的信号量集,我们可以理解为一个信号量的数组。
-
2. 对已创建的信号量集执行semget时,如果nsems和创建时不一致,semget返回-1。
-
/* 控制信号量集 */
-
int semctl(int semid, int semnum, int cmd, ...);
-
semid: semget返回的。
-
semnum: 操作单个信号量时,信号量的编号(可理解为信号量数组的下标)。编号从0开始,例如:semget时nsems=3, 那semnum的范围就是0~2。
-
cmd: SETVAL IPC_STAT IPC_SET GETALL SETALL IPC_INFO IPC_RMID(删除信号量集)。
-
arg4: union semun { /* 需要自行定义,内容视cmd参数而定。 */
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) */
};
-
注意: 1. 当cmd为SETALL/GETALL时,semnum参数失效,函数会将array数组的值逐一赋给每个信号量,并作为单个信号量的初值。当array数组短于信号量数组时,后面的信号量初值=0。长于信号量数组时,以信号量数组长度为准。
-
/* 操作信号量 */
-
int semop(int semid, struct sembuf *sops, unsigned nsops);
-
int semtimedop(int semid, struct sembuf *sops, unsigned nsops, struct timespec *timeout);
-
1. 函数执行操作集中指定的操作(sops->sem_op),增加或者减少信号量的值。
-
如果计数小于0(信号量的值是不能小于0的),那么这个信号量就不能再减小,而是会让调用线程/进程阻塞,直到信号量值为0或更大为止。
-
2. 函数原子地执行在sops中所包含的操作,也就是说:只有在这些操作可以同时成功执行时,这些操作才会被同时执行。
-
return: If successful semop() and semtimedop() return 0; otherwise they return -1 with errno indicating the error.
-
semid: 不再描述。
-
sops: 这个参数实质上是一个结构体指针,这个结构体描述了单个信号量需要进行的操作。
-
当需要同时操作多个信号量的时候,可以传入结构体数组。
-
struct sembuf {
-
unsigned short sem_num; /* 信号量的编号,类似semctl参数semnum */
short sem_op; /* 信号量PV操作,eg:=+2 =-1 */
short sem_flg; /* IPC_NOWAIT and SEM_UNDO */
-
}
-
nsops: 同时进行操作的元素个数,值>=1。简单来说,可以理解为sops指针指向的结构体个数。
二、例程
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
-
#include <sys/types.h>
-
#include <errno.h>
-
-
#include <sys/types.h>
-
#include <sys/ipc.h>
-
#include <sys/sem.h>
-
-
union semun {
-
int val;
-
struct semid_ds *buf;
-
unsigned short *array;
-
};
-
-
int main( int argc, char *argv[])
-
{
-
u_int32_t key = 0xFF00FF00;
-
-
int semhd = semget( key, 3, IPC_CREAT|IPC_EXCL|666);
-
if( semhd <= 0) {
-
printf("semget fault. %d. %s.\n", semhd, strerror(errno));
-
exit(1);
-
}
-
-
/* 设置单个信号量 */
-
union semun semun_val;
-
semun_val.val = 3;
-
semctl( semhd, 1, SETVAL, semun_val);
-
-
/* 批量设置信号量 */
-
unsigned short val_array[3] = { 5, 6, 7};
-
semctl( semhd, 0, SETALL, &val_array[0]);
-
-
printf("%d\n", semctl( semhd, 0, GETVAL, 0));
-
printf("%d\n", semctl( semhd, 1, GETVAL, 0));
-
printf("%d\n", semctl( semhd, 2, GETVAL, 0));
-
-
/* 信号量PV操作 */
-
struct sembuf sops[2];
-
sops[0].sem_num = 1;
-
sops[0].sem_op = -1;
-
sops[0].sem_flg = SEM_UNDO;
-
-
sops[1].sem_num = 2;
-
sops[1].sem_op = -2;
-
sops[1].sem_flg = SEM_UNDO;
-
-
semop( semhd, &sops[0], 2);
-
-
printf("%d\n", semctl( semhd, 0, GETVAL, 0));
-
printf("%d\n", semctl( semhd, 1, GETVAL, 0));
-
printf("%d\n", semctl( semhd, 2, GETVAL, 0));
-
-
semctl( semhd, 0, IPC_RMID);
-
return 0;
-
}
//END
阅读(1128) | 评论(0) | 转发(0) |