二、信号量集(system v ipc)
信号量集就是数组,数组里的每个元素都是信号量的类型
1、获取键值
ftok(3)
2、使用键值获取信号量集的id
semget(2)
#include
#include
#include
int semget(key_t key, int nsems, int semflg);
功能:获取信号量集的id
参数:
key:ftok(3)的返回值
nsems:指定了信号量集中的元素的个数
semflg:
IPC_CREAT
IPC_EXCL
mode:指定信号量集的权限
返回值:非负整数 是信号量集的id
-1 错误errno被设置
3、设置信号量集中的信号量的初值或者获取信号量的值
semctl(2)
#include
#include
#include
int semctl(int semid, int semnum, int cmd, ...);
功能:信号量的控制操作(得到一个信号量集标识符或创建一个信号量集对象并返回信号量集标识符)
参数:
semid:指定了信号量集
semnum:指定了信号量在数组中的下标
cmd:指定了对信号量的控制操作命令
GETVAL:第几个信号的semval值
SETVAL:设置第几个信号量的semval值为arg,val。 0
...:这个参数有没有,多少个取决于cmd
返回值:成功 返回一个正数
失败 -1 errno返回
需要自定义:
union semun {
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) */
};
4、对指定的信号量对指定的信号量加法或者减法操作
semop(2)
#include
#include
#include
int semop(int semid, struct sembuf *sops, unsigned nsops);
功能:信号量操作
参数:
semid:指定了信号量集
sops:指定了对某个信号量的具体操作
nsops:指定了要操作的信号量的个数
返回值:0 成功
-1 错误 errno被设置
操作定义在这个结构体中:
struct sembuf{
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
}
sem_flg:
SEM_UNDO:进程终止自动撤销
IPC_NOWAIT:
sem_num:指定了要操作的信号量在数组的下标
sem_op:指定了操作的类型
操作类型分为3种:
>0: semval+sem_op demval做加法
=0:
<0:
semval>|sem_op|:这个操作立即执行,
semval<|sem_op|
申请的资源数>可用资源数,IPC_NOWAIT 非阻塞
sem_flg=0 阻塞等待资源时间
举例说明:使用信号量集实现进程间的通信
两个进程 PA.C(设置信号量的值,每隔3s semval的值减一) PB.C(每隔1s获取信号量的值)
PA.c:
#include
#include
#include
#include
typedef union semun{
int val;
}semun_t;
int main(void){
key_t key;
struct sembuf sb={0,-1,IPC_NOWAIT};
semun_t arg;
//获取键值
key=ftok(".",31);
if(key==-1){
perror("ftok");
return -1;
}
//使用键值获取信号量集的id
int semid=semget(key,1,IPC_CREAT|0664);
if(semid==-1){
perror("semget");
return -1;
}
arg.val=5;
//设置信号量的初值
int ctl=semctl(semid,0,SETVAL,arg);
if(ctl==-1){
perror("semctl");
return -1;
}
//每隔三秒第一个信号量的值减1
while(1){
sleep(3);
int op=semop(semid,&sb,1);
if(op==-1){
perror("semop");
return -1;
}
}
return 0;
}
PB.c:
#include
#include
#include
#include
int main(void){
key_t key;
//获取键值
key=ftok(".",31);
if(key==-1){
perror("ftok");
return -1;
}
//使用键值获取信号量集的id
int semid=semget(key,1,IPC_CREAT|0664);
if(semid==-1){
perror("semget");
return -1;
}
//每隔一秒取一次信号量的值
while(1){
sleep(1);
int val=semctl(semid,0,GETVAL);
if(val==-1){
perror("semctl");
return -1;
}
printf("semval=%d\n",val);
}
return 0;
}