Linux IPC之信号量

创建一个信号量

//创建之后一直存在,除非主动删除
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.

你可能感兴趣的:(Linux IPC之信号量)