美文网首页
Linux IPC之信号量

Linux IPC之信号量

作者: 温柔倾怀 | 来源:发表于2021-01-26 20:48 被阅读0次

    创建一个信号量

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

          本文链接:https://www.haomeiwen.com/subject/yosnzktx.html