zoukankan      html  css  js  c++  java
  • Linux 进程间通信 信号灯集

    1.特点:  信号灯集,是控制访问临界资源

    信号灯(semaphore),也叫信号量。它是不同进程间或一个给定进程内部不同线程间同步的机制System V的信号灯是一个或者多个信号灯的一个集合(允许对集合中的多个计数信号灯进行同时操作)。其中的每一个都是单独的计数信号灯。而Posix信号灯指的是单个计数信号灯

    2.信号灯种类:
      posix有名信号灯
      posix基于内存的信号灯(无名信号灯)(线程)
      System V信号灯(IPC对象)(信号灯的值就是代表资源的数量)

    3.创建步骤:
      1)产生key值
      2)创建信号灯集
      3)初始化信号灯(对信号灯集中的每个信号灯进行初始化)
      4)信号灯的P-V操作
      5)删除信号灯集

    4.相关函数:
      1)int semget(key_t key, int nsems, int semflg);
        功能:创建/打开信号灯
        参数:key:ftok产生的key值(和信号灯关联的key值)
             nsems:信号灯集中包含的信号灯数目
             semflg:信号灯集的访问权限,通常为IPC_CREAT |0666
        返回值:成功:信号灯集ID ; 失败:-1

      2)int semop ( int semid, struct sembuf *opsptr, size_t nops);
        功能:对信号灯集合中的信号量进行P - V操作
        参数:semid:信号灯集ID
             struct sembuf {
            short sem_num; // 要操作的信号灯的编号
            short sem_op; // 0 : 等待,直到信号灯的值变成0 // 1 : 释放资源,V操作 // -1 : 分配资源,P操作 
            short sem_flg;  // 0(阻塞),IPC_NOWAIT, SEM_UNDO
             };//对某一个信号灯的操作,如果同时对多个操作,则需要定义这种结构体数组

             nops: 要操作的信号灯的个数 ,1个
        返回值:成功 :0 ; 失败:-1


          用法:semop(semid, &mysembuf, 1);
          申请资源 P操作:
            mysembuf.sem_num = 0;
            mysembuf.sem_op = -1;
            mysembuf.sem_flg = 0;
          释放资源 V操作:
            mysembuf.sem_num = 0;
            mysembuf.sem_op = 1;
            mysembuf.sem_flg = 0;

    3)int semctl ( int semid, int semnum, int cmd…/*union semun arg*/);
      功能:信号灯集合的控制(初始化/删除)
      参数:semid:信号灯集ID
           semnum: 要操作的集合中的信号灯编号
           cmd:
          GETVAL:获取信号灯的值,返回值是获得值
          SETVAL:设置信号灯的值,需要用到第四个参数:共用体
          IPC_RMID:从系统中删除信号灯集合
      返回值:成功 0 ; 失败 -1


      用法:
      初始化:semctl(semid, 0, SETVAL, mysemun);
      需要在程序中定义共用体
      获取信号灯值:semctl(semid, 0, GETVAL);
      删除信号灯集:semctl(semid, 0, IPC_RMID);

    例子: 简单对信号灯的操作(多值信号灯)

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    #include <errno.h>
    
    int semid; //信号灯集id, 通过这个id 操作这个信号灯集,在不同进程中,操作同一个信号灯集的id
    union semnum  
    {
        int val;
    };
    
    union semnum mynum; 
    struct sembuf mybuf; //定义操作信号灯的结构
    
    //参数 信号灯集id 和 是哪个信号灯
    void sem_p(int semid, unsigned short num) //P操作函数
    {
        mybuf.sem_num = num; //第一个信号灯,(信号灯编号)
        mybuf.sem_op = -1; //进行P操作, 为 1 时表示V操作
        mybuf.sem_flg = 0; //阻塞
        semop(semid, &mybuf, 1); //最后一个参数,表示操作信号灯的个数
    }
    
    //参数 信号灯集id 和 是哪个信号灯
    void sem_v(int semid, unsigned short num) //V操作函数
    {
        mybuf.sem_num = num;
        mybuf.sem_op = 1;  //1 表示V 操作
        mybuf.sem_flg = 0; //阻塞
        semop(semid, &mybuf, 1);  //操作的 mybuf 全部变量信号灯集
    }
    
    int main(int argc, const char *argv[])
    {
        key_t key;
        key = ftok("app",'m');//获取唯一的 key 
        if(key < 0)
        {
            perror("fail fptk ");
            exit(1);
        }
        //int semget(key_t key, int nsems, int semflg);
        //IPC_EXCL | IPC_CREAT 信号灯不存在就创建
        semid = semget(key, 2, IPC_CREAT|IPC_EXCL|0666); //创建信号灯,IPC_EXCL 问信号灯存不存在
        if(semid < 0)
        {
            if(errno == EEXIST)//存在时,只需要打开即可
            {
                semid = semget(key,2,0666); //打开信号灯
            }
            else
            {
                perror("semget fail ");
            }
        }
        else
        {
        //    int semctl(int semid, int semnum, int cmd, ...);
            mynum.val = 10;  //设置信号灯值
            semctl(semid,0,SETVAL,mynum); //初始化 0 号信号灯,此处使用共用体设置信号灯值,初始化完成后可以继续给下一个信号灯设置值
            
            mynum.val = 5; //设置信号灯值
            semctl(semid,1,SETVAL,mynum); //初始化 1 号信号灯,把设置的信号灯值给1号信号灯
        }
        sem_p(semid, 0); //对semid 指向的信号灯集,中0号信号灯进行P操作
        sem_p(semid, 0); //对semid 指向的信号灯集,中0号信号灯进行P操作
        sem_p(semid, 0); //对semid 指向的信号灯集,中0号信号灯进行P操作
        printf("%d
    ",semctl(semid, 0, GETVAL)); //上面对 0 信号灯初始值 10 进行流三次P 操作,此时应该为 7
        printf("%d
    ",semctl(semid, 1, GETVAL)); //没有对 1 信号灯操作,其值不变为 5
        putchar(10);
    
        sem_v(semid,1);
        printf("%d
    ",semctl(semid, 1, GETVAL)); //上面对 1 信号灯 V 操作,其值变为 6
        
        semctl(semid,0,IPC_RMID);//删除信号灯
        return 0;
    }

    测试:对于多值信号灯可以进行多次P操作

     

             

  • 相关阅读:
    dubbo服务provider方打印警告日志,getDeserializer
    [学习]sentinel中的DatatSource(一) ReadableDataSource
    ppt字体
    dubbo异常filter
    术语
    [转]五步git操作搞定Github中fork的项目与原作者同步
    markdown学习资料
    springboot properties
    aop备忘
    git技巧
  • 原文地址:https://www.cnblogs.com/electronic/p/10946255.html
Copyright © 2011-2022 走看看