1 semget()
查看系统当前的信号量:
利用ipcs命令显示semaphore arrays
ipcrm -s semid 删除“semid”
头文件:#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
函数原型:int semget(key_t key, int nsems, int semflg);
功能描述:
得到一个信号量集标识符或创建一个信号量集对象并返回信号量集标识符
Key:
若系统中已经存在key值则获取信号量的标识符,若不存在则视参数semflg来新建一个信号量集,并返回新建信号量集的标识符。
Nsems:
创建信号量集中信号量的个数,该参数只在创建信号量集时有效
Msgflg:(一般为IPC_CREAT | 0664 ,0664决定了其属性 )
0:取信号量集标识符,若不存在则函数会报错
IPC_CREAT:当semflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的信号量集,则新建一个信号量集;如果存在这样的信号量集,返回此信号量集的标识符
IPC_CREAT | IPC_EXCL:如果内核中不存在键值与key相等的信号量集,则新建一个消息队列;如果存在这样的信号量集则报错
函数返回值
成功:返回信号量集的标识符
出错:-1,错误原因存于error中
附加说明
上述semflg参数为模式标志参数,使用时需要与IPC对象存取权限(如0600)进行 |运算来确定信号量集的存取权限
错误代码
EACCESS:没有权限
EEXIST:信号量集已经存在,无法创建
EIDRM:信号量集已经删除
ENOENT:信号量集不存在,同时semflg没有设置IPC_CREAT标志
ENOMEM:没有足够的内存创建新的信号量集
ENOSPC:超出限制
2 semgctl()
头文件:#include<sys/sem.h>
原 型:int semctl(int semid, int semnum, int cmd, /* union semun arg */);
返回值:如果成功,则为一个正数。
如果失败,则为-1:errno = EACCES(权限不够)
EFAULT(arg指向的地址无效)
EIDRM(信号量集已经删除)
EINVAL(信号量集不存在,或者semid无效)
EPERM(EUID没有cmd的权利)
ERANGE(信号量值超出范围)
因为信号量一般是作为一个信号量集使用的,而不是一个单独的信号量。所以在信号量集的操作中,不但要知道IPC关键字值(即key),也要知道信号量集中的具体的信号量。这两个系统调用都使用了参数cmd,它用来指出要操作的具体命令。两个系统调用中的最后一个参数也不一样。在系统调用msgctl中,最后一个参数是指向内核中使用的数据结构的指针。我们使用此数据结构来取得有关消息队列的一些信息,以及设置或者改变队列的存取权限和使用者。但在信号量中支持额外的可选的命令,这样就要求有一个更为复杂的数据结构。
参数:
系统调用semctl()的第一个参数semid是信号量集IPC标识符(semget的返回值)。
第二个参数semnum是操作信号在信号集中的编号,第一个信号的编号是0。
参数cmd中可以使用的命令如下:
·IPC_STAT读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
·IPC_SET设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
·IPC_RMID 将信号量集从内存中删除。
·GETALL 用于读取信号量集中的所有信号量的值。
·GETNCNT 返回正在等待资源的进程数目。
·GETPID 返回最后一个执行semop操作的进程的PID。
·GETVAL 返回信号量集中的一个单个的信号量的值。
·GETZCNT 返回这在等待完全空闲的资源的进程数目。
·SETALL 设置信号量集中的所有的信号量的值。
·SETVAL 设置信号量集中的一个单独的信号量的值。//常用于单个信号量的初始化
参数arg代表一个semun的实例。semun是在linux/sem.h中定义的:
/*arg for semctl systemcalls.*/
union semun
{
int val; /*value for SETVAL信号量的值*/
struct semid_ds *buf; /*buffer for IPC_STAT&IPC_SET*/
ushort *array; /*array for GETALL&SETALL*/
}
val当执行SETVAL命令时使用(初始化的时候通常令val=0)。buf在IPC_STAT/IPC_SET命令中使用。代表了内核中使用的信号量的数据结构。array在使用GETALL/SETALL命令时使用的指针。
3 semop()
int semop(int semid,struct sembuf *sops,size_t nsops);
功能描述
操作一个或一组信号。
用法
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, size_t nops);
参数
semid:信号集的标识符,可通过semget获取。
sops:指向存储信号操作结构的数组指针,信号操作结构的原型如下
struct sembuf
{
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
};
这三个字段的意义分别为:
sem_num:操作信号在信号集中的编号,第一个信号的编号是0。
sem_op: 如果其值为正数,该值会加到信号值中。通常用于释放所控资源的使用权;如果sem_op的值为负数,而其绝对值又大于目前信号值,操作将会阻塞,直到信号值大于或等于sem_op的绝对值。通常用于获取资源的使用权;如果sem_op的值为0,则操作将暂时阻塞,直到信号的值变为0。(信号值val在semgctl中初始化)
sem_flg:信号操作标志,可能的选择有两种
IPC_NOWAIT :对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误信息。
SEM_UNDO :程序结束时(不论正常或不正常),保证信号值会被重设为semop()调用前的值。这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定。
nops:信号操作结构的数量,恒大于或等于1。
返回说明
成功执行时,两个系统调用都返回0。失败返回-1,errno被设为以下的某个值
E2BIG:一次对信号的操作数超出系统的限制
EACCES:调用进程没有权能执行请求的操作,且不具有CAP_IPC_OWNER权能
EAGAIN:信号操作暂时不能满足,需要重试
EFAULT:sops或timeout指针指向的空间不可访问
EFBIG:sem_num指定的值无效
EIDRM:信号集已被移除
EINTR:系统调用阻塞时,被信号中断
EINVAL:参数无效
ENOMEM:内存不足
ERANGE:信号所允许的值越界
例1:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int main()
{
int rt;
int semid;
int n = 1;
semid = semget(2,2,IPC_CREAT|0664);
if(-1 == semid)
{
fprintf(stderr,"semget fail\n");
return -1;
}
n = semctl(semid,0,SETVAL,1);
if(-1 == n)
{
fprintf(stderr,"semctl fail\n");
return -1;
}
n = semctl(semid,1,SETVAL,0);
if(-1 == n)
{
fprintf(stderr,"semctl fail\n");
return -1;
}
return 0;
}
例2
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int main()
{
int n;
int i;
int semid;
FILE *fp;
struct sembuf sem[1];
semid = semget(0x60000,0,0);
if(-1 == semid)
{
fprintf(stderr,"semget fail\n");
return -1;
}
fp = fopen("test","r+");
if(NULL == fp )
{
fprintf(stderr,"open file fail\n");
return -1;
}
sem[0].sem_num = 0;
sem[0].sem_flg = 0;
sem[0].sem_op = -1;
for(i = 0;i < 500000;i++)
{
sem[0].sem_op = -1;
semop(semid,sem,1);
fseek(fp,0,SEEK_SET);
fscanf(fp,"%d",&n);
n++;
fseek(fp,0,SEEK_SET);
fprintf(fp,"%d",n);
fflush(fp);
sem[0].sem_op = 1;
semop(semid,sem,1);
}
printf("game over\n");
fclose(fp);
}