#include <sys/sem.h>
int semget(key_t key, int nsems, int oflags);返回一个信号灯的标识符。
nsems指定集合中的信号灯数,如果只是打开一个已存在的集合,则该参数指定为0.创建完一个信号灯集,就不能改变其中的信号灯数。
oflags值是SEM_R和SEM_A常值的组合。也可以与IPC_CREAT或IPC_CREAT|IPC_EXCL组合。
semctl函数对一个信号灯执行各种控制操作。
int semctl(int semid, int semnum, int cmd, ...);
semid标识待控制其操作的信号灯集,semnum标识该信号灯集中的第semnum个(从0开始)成员,semnum值仅仅用于GETVAL、SETVAL、GETNCNT、GETZCNT和GETPID命令。
System V支持下列cmd值:
GETVAL,SETVAL,GETPID,GETNCNT,GETZCNT,GETALL,SETALL,IPC_RMID,IPC_SET,IPC_STAT
对于系统中的每个信号灯集,内核维护一个如下的信息结构:
struct semid_ds
{
struct ipc_perm sem_perm; // operation permission
struct sem *sem_base; // ptr to array of semaphores in set
unsigned short sem_nsems; // number of semaphres in set
time_t sem_otime; // time of last semop()
time_t sem_ctime; // time of creation or last IPC_SET
};
其中,struct sem结构如下:
struct sem
{
unsigned short semval; // semaphore value, nonnective
short sempid; // pid of last seccessful semop(),
// SETVAL,SETALL
unsigned short semncnt; // awaiting semval > current value
unsigned short semzcnt; // awaiting semval = 0
};
*) GETVAL 把semval的当前值作为函数返回值返回;
*) SETVAL 把semval的值设置为arg.val;*) GETPID 返回sempid的当前值
*) GETNCNT 把semncnt的当前值返回
*) GETZCNT 把semzcnt的当前值返回
*) GETALL 把指定信号灯集中的每个成员的semval值返回,调用者必须分配足够容纳所指定信号灯集中所有成员的semval值的一个unsigned short整数数组,然后把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结构。调用者必须首先分配一个semid_ds结构,并把arg.buf设置成指向这个结构。
使用semget打开一个信号灯集合后,对其中的一个或多个信号灯的操作就使用semop函数来执行。
int semop(int semid, struct sembuf *opsptr, size_t nops);
semop函数用来对一个或多个信号灯进行操作。
其中struct sembuf结构为:
struct sembuf
{
short sem_num; // semaphores number
short sem_op; // semaphores operations
short sem_flg; // operation flags: 0, IPC_NOWAIT, SEM_UNDO
};
nops参数指出由opsptr指向的sembuf结构数组中元素的数目。
// semcreat.c
#include <sys/types.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <unistd.h>
#define SVSEM_MODE 0644
int main(int argc, char **argv)
{
int c, oflag, semid, nsems;
oflag = SVSEM_MODE | IPC_CREAT;
while((c = getopt(argc, argv, "e")) != -1)
{
switch(c)
{
case 'e':
oflag |= IPC_EXCL;
break;
}
}
if(optind != argc - 2)
{
perror("usage: semcreat [-e] <pathname> <nsems>");
exit(0);
}
nsems = atoi(argv[optind + 1]);
semid = semget(ftok(argv[optind], 0), nsems, oflag);
return 0;
}
// semgetvalues.c
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <stdio.h>
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
};
int main(int argc, char **argv)
{
int semid, nsems, i;
struct semid_ds seminfo;
unsigned short *ptr;
union semun arg;
if(argc != 2)
{
perror("usage: semgetvalues <pathname>");
exit(0);
}
semid = semget(ftok(argv[1], 0), 0, 0);
arg.buf = &seminfo;
semctl(semid, 0, IPC_STAT, arg);
nsems = arg.buf->sem_nsems;
ptr = calloc(nsems, sizeof(unsigned short));
arg.array = ptr;
semctl(semid, 0, GETALL, arg);
for(i = 0; i < nsems; i++)
printf("semval[%d] = %d\n", i, ptr[i]);
return 0;
}
// semops.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <unistd.h>
union semun
{
int va;
struct semid_ds *buf;
unsigned short *array;
};
int main(int argc, char **argv)
{
int c, i, flag, semid, nops;
struct sembuf *ptr;
flag = 0;
while((c = getopt(argc, argv, "nu")) != -1)
{
switch(c)
{
case 'n':
flag |= IPC_NOWAIT;
break;
case 'u':
flag |= SEM_UNDO;
break;
}
}
if(argc - optind < 2)
{
perror("usage: semops [-n] [-u] <pathname> operation ...");
exit(0);
}
semid = semget(ftok(argv[optind], 0), 0, 0);
optind++;
nops = argc - optind;
ptr = calloc(nops, sizeof(struct sembuf));
for(i = 0; i < nops; i++)
{
ptr[i].sem_num = i;
ptr[i].sem_op = atoi(argv[optind + i]);
ptr[i].sem_flg = flag;
}
semop(semid, ptr, nops);
return 0;
}
// semid.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int semid;
if(argc != 2)
{
perror("usage: semid <pathname>");
exit(0);
}
semid = semget(ftok(argv[1], 0), 0, 0);
semctl(semid, 0, IPC_RMID);
exit(0);
}
// semsetvalues.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <sys/sem.h>
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
};
int main(int argc, char **argv)
{
int semid, nsems, i;
struct semid_ds seminfo;
unsigned short *ptr;
union semun arg;
if(argc < 2)
{
perror("usage: semsetvalues <pathname> [values ...]");
exit(0);
}
semid = semget(ftok(argv[1], 0), 0, 0);
arg.buf = &seminfo;
semctl(semid, 0, IPC_STAT, arg);
nsems = arg.buf->sem_nsems;
if(argc != nsems + 2)
{
perror("%d semaphores in set, %d values specified", nsems, argc - 2);
exit(0);
}
ptr = calloc(nsems, sizeof(unsigned short));
arg.array = ptr;
for(i = 0; i < nsems; i++)
ptr[i] = atoi(argv[i + 2]);
semctl(semid, 0, SETALL, arg);
return 0;
}
[test@localhost] touch info
[test@localhost] ./semcreat -e info 3
[test@localhost] ./semsetvalues info 1 2 3
[test@localhost] ./semgetvalues info
semval[0] = 1
semval[1] = 2
semval[2] = 3
[test@localhost] ./semops -u info -1 -2 -3 # 给每个操作指定SEM_UNDO标志
[test@localhost] ./semgetvalues info
semval[0] = 1 # 当semops终止时,所有变动都取消
semval[1] = 2
semval[2] = 3
[test@localhost] ./semops info -1 -2 -3 # 不指定SEM_UNDO标志
[test@localhost] ./semgetvalues info
semval[0] = 0 # 变动未被取消
semval[1] = 0
semval[2] = 0