结构:
int semget(key_t key, int nsems, int semflg)
举例:
//创建一个只包含一个信号量的信号量集
int m = semget(IPC_PRIVATE, 1, 0661|IPC_CREAT)
作用:
创建或者打开一个已经创建的信号量集,执行成功返回信号量的ID,否则返回-1。
参数说明:
key:
-使用IPC_PRIVATE,由系统产生key值并返回标识符,或者返回key值已存在的信号量集的标识符。
-用户指定一个非0整数型值,对信号量的打开或者存取操作依赖于semflg参数的取值。
nsems:
-新建信号量集中的信号量的个数,通常为1
semflg:
-对信号量的打开或者存取操作依赖于semflg参数的取值,
-当key不为IPC_PRIVATE时使用
-若只创建了semflg的IPC_CREAT位,则创建一个信号量集,如果该信号量集已经存在,则返回其标识符。
-semflg的IPC_CREAT|IPC_EXCL位,则创建一个新的信号量集,如果该key值的信号量已经存在,则返回错误信息。
-只设置IPC_EXCL而不设置IPC_CREAT位没有任何意义
返回值:
正确返回信号量集的标识符,错误时返回-1。
semop
函数:
int semop(int semid, struct sembuf *sops, unsigned nsops)
功能:
借助sembuf结构体对指定的信号量进行指定的操作,增加或减少信号量值,对应于共享资源的释放和占有。执行成功返回0,否则返回-1.
参数说明:
semid:
-信号量集的标识符,有senget()得到
sops:
-指向一个sembuf结构数组(下面介绍),该数组的每一个元素对应一次信号量操作
sembuf结构体
作用:
struct sembuf{
ushort sem_num; //要操作的信号量在信号量集中的索引值
short sem_op; //负数表示P操作,正数表示V操作
short sem_flg; //操作标志,SEM_UNDO,进程意外结束时恢复信号量的操作
}
semctl
功能:
对信号量属性进行操作,调用成功返回结果与cmd(指定的操作类型)相关,调用失败返回-1.
函数:
int semctl(int semid, int semnum, int cmd, union semun arg);
举例:
int semid = semget(IPC_PRIVATE, 1, 0666|IPC_CREAT);
semctl(semid,0,SETVAL,1);
参数说明:
semid:
-是信号量集的标识符,有semget()得到
semnum:
-指定semid信号量集的第几个信号量,在撤销信号量集时此参数可缺省
-要操作的信号量集中信号量的索引值,对于集合上的第一个信号量该值为0
cmd:
指定操作类型
-取值 -含义
GETVAL 返回semnum指定的信号量的semval阈值
SETVAL 指定semval域值为arg.val
GETPID 返回semnum指定信号量sempid
GETNCNT 返回semncnt
GETZCNT 返回semzcnt
GETALL 返回所有信号量的值,结果保存到arg.array中
SETALL 通过arg.array更新所有信号量的值
IPC_STAT 获取信号量集的arg.array,存入arg.buf
IPC_SET 将arg.buf数据结构的sem_perm.uid,sem_perm.gid,sem_perm.mode赋给sem_array,此操作仅限root、sem_perm.cuid或sem_perm.uid
IPC_RMID 删除指定信号量集。此操作仅限root、sem_perm.cuid或sem_perm.uid
IPC_INFO 获取信号量集的相关信息存放于arg.buf中
arg:
-为5种数据类型的共同体类型semnu,该类型在include/linux/sem.h中定义
union senum
{
int val; /*value for setval*/
struct semi_ds *buf; /*buffer for IPC_STAT & IPC_SET*/
unsigned short *array; /*array for GETALL & SETALL*/
struct seminfo *_buf; /*buffer for IPC_INFO*/
void *_pad
};
-撤销信号量集
semctl(semid ,IPC_RMID ,0)
定义信号量标志符:int semid;
定义信号量数据结构
定义PV操作所用的数据结构:struct sembuf P,V;
定义给信号量赋初值的参数数据结构:union semun arg;
申请一个信号量的信号量集
对每一个信号量semid赋初值
定义信号量的P操作
定义信号量的V操作
执行PV操作
撤销信号量
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*
父子进程共享一个临界资源(这里就是stdout),
每个进程循环进入临界区3次
父进程进入后显示parent in
父进程出去后显示parent out
子进程进入后显示chld in
子进程出去后显示chld out
*/
union semun{
int val;
struct semid_ds *buf;
unsigned short *array;
};
int mutexid; //互斥信号量
int main()
{
int chld,i,j;
struct sembuf P,V;
union semun arg;
/*****申请只有一个信号量的信号量集*****/
mutexid=semget(IPC_PRIVATE,1,0666|IPC_CREAT);
/*****分别对每个信号量赋初值*****/
arg.val=1;
if(semctl(mutexid,0,SETVAL,arg)==-1)
perror("semctl setval error");
/*****定义PV操作*****/
P.sem_num=0;
P.sem_op=-1;
P.sem_flg=SEM_UNDO;
V.sem_num=0;
V.sem_op=1;
V.sem_flg=SEM_UNDO;
while((chld=fork())==-1);
if(chld>0)
{/*****父进程块*****/
i=1;
while(i<=3)
{
sleep(1);
semop(mutexid,&P,1); /*占有临界资源*/
printf("parent in\n");
sleep(1);
printf("parent out\n");
semop(mutexid,&V,1); /*释放临界资源*/
i++;
}
wait(0);
/*****撤销信号量集*****/
semctl(mutexid,IPC_RMID,0);
exit(0);
}else{
/*****子进程块*****/
j=1;
while(j<=3)
{
sleep(1);
semop(mutexid,&P,1);
printf("chld in\n");
sleep(1);
printf("chld out\n");
semop(mutexid,&V,1);
j++;
}
exit(0);
}
}
2、利用信号量实现进程同步
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*
父子进程共用一个存储区,
子进程写入信息,父进程
读取信息。
*/
union semun{
int val;
struct semid_ds *buf;
unsigned short *array;
};
int emptyid;
int fullid; //同步信号量
main()
{
int chld;
struct sembuf P,V;
union semun arg;
int shmid;
char *viraddr;
char buffer[BUFSIZ];
/*****申请只有一个信号量的信号量集*****/
emptyid=semget(IPC_PRIVATE,1,IPC_CREAT|0666);
fullid=semget(IPC_PRIVATE,1,IPC_CREAT|0666);
/*****分别对每个信号量赋初值*****/
arg.val=1;
if(semctl(emptyid,0,SETVAL,arg)==-1)
perror("semctl setval error");
arg.val=0;
if(semctl(fullid,0,SETVAL,arg)==-1)
perror("semctl setval error");
/*****定义PV操作*****/
P.sem_num=0;
P.sem_op=-1;
P.sem_flg=SEM_UNDO;
V.sem_num=0;
V.sem_op=1;
V.sem_flg=SEM_UNDO;
/*****申请共享内存空间*****/
shmid=shmget(IPC_PRIVATE,BUFSIZ,0666|IPC_CREAT);
viraddr=(char*)shmat(shmid,0,0);
while((chld=fork())==-1);
if(chld>0)
{
while(1)
{
semop(fullid,&P,1);
printf("Your message is:\n%s",viraddr);
semop(emptyid,&V,1);
if(strncmp(viraddr,"end",3)==0)break;
}
wait(0);
shmdt(viraddr);
/*****撤销信号量集、释放共享内存*****/
shmctl(shmid,IPC_RMID,0);
semctl(emptyid,IPC_RMID,0);
semctl(fullid,IPC_RMID,0);
printf("Parent exit!\n");
exit(0);
}
else
{
while(1)
{
semop(emptyid,&P,1);
puts("Enter your text:");
fgets(buffer,BUFSIZ,stdin);
strcpy(viraddr,buffer);
semop(fullid,&V,1);
if(strncmp(viraddr,"end",3)==0)
{
sleep(1);
break;
}
}
printf("Child exit!\n");
exit(0);
}
}