1. semget
int semget( key_t key, int nsems, int flag);
信号量集被建立的情况有两种:
1.如果键的值是IPC_PRIVATE
2.键的值不是IPC_PRIVATE,并且键所对应的信号量集不存在,同时标志中指定IPC_CREATflag:
1.单独使用IPC_CREAT,要么返回新创建的信号量集的标识符,要么返回系统中已经存在的同样的关键字值的信号量的标识符
2.IPC_EXCL和IPC_CREAT一同使用,要么返回新创建的信号量集的标识符,要么返回-1
3.IPC_EXCL单独使用没有意义nsems:新的信号量集中应该创建的信号量的个数(最多的信号量的个数在linux/sem.h中定义)
struct semid_ds
{
struct ipc_perm sem_perm;
unsigned short sem_nsems; /* # of semaphore in set */
time_t sem_otime; /* last-semop() time */
time_t sem_ctime; /* last-change time */
…
};
struct ipc_perm
{
uid_t uid; /* owner’s effective user id */
gid_t gui; /* owner’s effective group id */
uid_t cuid; /* creator’s effective user id */
gid_t cgid; /* creator’s effective group id */
mode_t mode; /* access mode */
…
};
如果是创建一个新的信号量集合,那么对semid_ds的成员进行初始化
1.ipc_perm中的mode被设置为flag中的相应权限位
2.sem_nsems设置为nsems
3.sem_otime设置为0
4.sem_ctime设置为当前时间
注意:如果创建新集合, 则必须指定nsems, 如果引用一个集合, 则nsems设定为0
2. semop
int semop(int semid, struct sembuf *sops, unsigned nsops);
struct sembuf
{
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
};
sem_num:操作信号在信号集中的编号,第一个信号的编号是0
sem_op:
1.如果sem_op是正数,则信号量加上它的值
2.如果sem_op是负数,那么信号量将减去它的值,如果没有使用>IPC_NOWAIT,操作将会阻塞,直到信号量控制的资源可以使用为止,通常用于获取资源的使用权
3.如果sem_op是0,操作将暂时阻塞,直到信号量的值为0,这在一个进程等待完全空闲的资源时使用sem_flg:
1.IPC_NOWAIT //对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误信息
2.SEM_UNDO //程序结束时(不论正常或不正常),保证信号值会被重设为semop()调用前的值。这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定(如果为sem_flg指定SEM_UNDO,Linux会在进程退出的时候自动撤销该次操作)nsops:信号操作结构的数量
3. semctl
int semctl(int semid, int semnum, int cmd, … /* union semun arg */)
union semun
{
int val; /* for SETVAL */
struct semid_ds *buf; /* for IPC_STAT and IPC_SET */
unsigned short *array; /* for GETALL and SETALL */
};
//无名结构体
struct {
unsigned short semval; /* semaphore value, always >= 0 */
pid_t sempid; /* pid for last operation */
unsigned short semncnt; /* # processes awaiting semval>curval */
unsigned short semzcnt; /* # processes awaiting semval == 0 */
…
};
cmd包括十种命令:
1.IPC_STAT
读取semid_ds到arg.buf
2.IPC_SET
将arg.buf设置到sem_perm.uid, sem_perm.gid和sem_perm.mode
3.IPC_RMID
将信号量集从内存中删除
4.GETVAL
返回semnum信号量的无名结构体的成员semval值
5.SETVAL
arg.val设置到由semnum信号量的无名结构体成员semval中
6.GETPID
返回无名结构体成员sempid,最后一个执行semop操作的进程的PID
7.GETNCNT
返回无名结构体成员semncnt,正在等待资源的进程数目
8.GETZCNT
返回无名结构体成员semzcnt,等待完全空闲的资源的进程数目
9.GETALL
取该集合中所有信号量(无名结构体)的值, 存放在arg.array指向的数组中
10.SETALL
将arg.array指向的数组的值设置该集合所有信号量的值(无名结构体)
注:semctl中的最后一个参数是一个联合类型的副本,而不是一个指向联合类型的指针
error详见百科
[test@localhost ~]$ ipcs -s
------ Semaphore Arrays --------
key semid owner perms nsems
0x0000eeee 1310730 test 660 2
key: semget中的key
semid: semget中创建成功返回值
owner: 创建者用户名
perms: semget中的flag
nsems: semget中的nsems (和semop中sops.sem_num息息相关,如果指定为1,sem_num只能操作一个信号量集)
4. 查看更详细信息
# ipcs [-s -m -q] -i id
# ipcs -s -i 32769
Semaphore Array semid=32769
uid=0 gid=0 cuid=0 cgid=0
mode=0600, access_perms=0600
nsems = 1
otime = Sun Aug 16 02:31:22 2015
ctime = Sun Aug 16 02:31:07 2015
semnum value ncount zcount pid
0 1 0 0 835
5. 例子
int main()
{
int ret = 0;
int semid = 0;
printf("%p\n", IPC_CREAT);
semid = semget(key, 2, IPC_CREAT | 0666);
if(semid < 0)
{
perror("semget");
}
struct sembuf sembuf[3] = {0};
sembuf[0].sem_num = 1;
sembuf[0].sem_op = 1;
// sembuf[0].sem_flg = SEM_UNDO; //4096
sembuf[0].sem_flg = IPC_NOWAIT; //2048
ret = semop(semid, sembuf, 1);
if(ret < 0)
{
perror("semop");
}
sembuf[0].sem_num = 1;
sembuf[0].sem_op = -2;
sembuf[0].sem_flg = 0;
ret = semop(semid, sembuf, 1);
if(ret < 0)
{
perror("semop");
}
semctl(semid, 1, IPC_RMID);
return 0;
}