创建一个信号量
//创建之后一直存在,除非主动删除
int sem_id;
//semget第二个参数为信号量集(数组)中信号量的个数
sem_id = semget(1000,1,IPC_CREAT|0600);
ERROR_CHECK(sem_id,-1,"semget");
将信号量初始化|设置信号量的值
//semctl函数
//第二个参数为信号量在信号量集(数组)中的下标
//初始化时,第三个参数为 SETVAL
//第四个参数为初始化的值
int ret = semctl(sem_id,0,SETVAL,1);
//成功返回0
ERROR_CHECK(ret,-1,"semctl");
获取信号量的值
ret = semctl(sem_id,0,GETVAL);
ERROR_CHECK(ret,-1,"semctl");
实现PV操作
//P定义一个结构体
//V定义一个结构体
struct sembuf sopp,sopv;
//P操作
sopp.sem_num = 0;
sopp.sem_op = -1;
sopp.sem_flag = SEM_UNDO;
//V操作
sopv.sem_num = 0;
sopv.sem_op = 1;
sopv.sem_flag = SEM_UNDO;
if(!fork())
{
for(int i=0;i<100000000;i++)
{
//加锁
semop(sem_id,&sopp,1);
p_start[0] = p_start[0]+1;
//解锁
semop(sem_id,&sopv,1);
}
}
参数cmd为执行的操作
- IPC_RMID 立即删除信号量,唤醒所有被阻塞的进程
- GETVAL 返回信号量的值,从0开始,第一个信号量编号为0
- SETVAL 设定信号量的值,从0开始,第一个信号量编号为0
删除信号量集合
//删除信号量集合
ret = semctl(sem_id,0,IPC_RMID);
ERROR_CHECK(ret,-1,"semctl");
批量设置多个信号量的值
unsigned short arrays[2]={0,10};
int ret = semctl(sem_id,0,SETALL,arrays);
生产者消费者
#include
int main(int argc,char*argv[])
{
int sem_id;
//两个信号量
sem_id = semget(1000,2,IPC_CREAT|0600);
ERROR_CHECK(sem_id,-1,"semctl");
//生产者消费者 计数信号量
//0号信号量代表产品数目
//1号信号量代表仓库数目
unsigned short arrays[2]={0,10};
int ret;
//对两个信号量同时进行初始化
ret = semctl(sem_id,0,SETALL,arrays);
ERROR_CHECK(ret,-1,"semctl");
//将arrays都设置为0
//memset(arrays,0,sizeof(arrays));
//子进程是出库进程,消费者
//父进程是入库进程,生产者
if(!fork()){
//出库,产品-,仓库空间+,故0号信号量p操作,1号信号量v操作
struct sembuf sopp0,sopv1;
sopp0.sem_num=0;
sopp0.sem_op=-1;
sopp0.sem_flg=SEM_UNDO;
sopv1.sem_num=1;
sopv1.sem_op=1;
sopv1.sem_flg=SEM_UNDO;
while(1){
//子进程出库
printf("I am Customer,product num = %d space num = %d \n",semctl(sem_id,0,GETVAL),semctl(sem_id,1,GETVAL));
//对产品-1 P操作
semop(sem_id,&sopp0,1);
printf("start out...\n");
//对仓库个数+1
semop(sem_id,&sopv1,1);
printf("I am Customer,product num = %d space num = %d \n",semctl(sem_id,0,GETVAL),semctl(sem_id,1,GETVAL));
sleep(2);
}
}else{
//入库
//产品+,仓库空间-, 0号信号量+1,1号信号量-1
struct sembuf sopp1,sopv0;
sopv0.sem_num=0;//在信号量集合中的编号
sopv0.sem_op=1;//V操作 +1
sopv0.sem_flg=SEM_UNDO;
sopp1.sem_num=1;
sopp1.sem_op=-1;
sopp1.sem_flg=SEM_UNDO;
while(1)
{
printf("I am Productor,product num = %d space num = %d\n",semctl(sem_id,0,GETVAL),semctl(sem_id,1,GETVAL));
//对仓库数-1,先要有位置了才能放入
semop(sem_id,&sopp1,1);
printf("start in...\n");
//产品数+1
semop(sem_id,&sopv0,1);
printf("I am Productor,product num = %d space num = %d\n",semctl(sem_id,0,GETVAL),semctl(sem_id,1,GETVAL));
sleep(1);
}
}
return 0;
}
SEM_UNDO
设置为SEM_UNDO,当杀掉一个进程的时候,这个进程对该某信号的操作会较初始值全部反向操作回去.(若P操作减了三十次,则较初始值加回三十)
若要减三十多次,不能减为负值,那就为0
PV的非计数信号量,需要用SEM_UNDO.