• Linux _sem 信号量 V_P


    信号量

    1. 问题
      程序中,有时存在一种特殊代码,
      最多只允许一个进程执行该部分代码。
      这部分区域,称为“临界区”

      然而在多进程并发执行时,当一个进程进入临界区,因某种原因被挂起时,
      其他进程就有可能也进入该区域。

      解决办法:使用信号量

    2. 什么是信号量
      信号量,是一种特殊的变量。
      只能对信号量执行P操作和V操作

      P操作, 如果信号量的值 > 0, 则把该信号量减1
      如果信号量的值 ==0, 则挂起该进程。

      V操作: 如果有进程因该信号量而被挂起,则恢复该进程运行
      如果没有进程因该信号量而挂起,则把该信号量加1

      注意:P操作、V操作都是原子操作,即其在执行时,不会被中断。

      注意:此指的“信号量”是指System V IPC的信号量,
      与线程所使用的信号量不同。
      该信号量,用于进程间通信。

    3. 信号量的使用

      1) 信号量的获取
      semget

      原型:int semget(key_t key,   int nsems,   int semflg);
      功能:获取一个已存在的、或创建一个新的信号量量,返回该信号量的标识符
      参数:key, 键值,该键值对应一个唯一的信号量。
                     类似于共享内存的键值。
                     不同的进程可通过该键值和semget获取唯一的信号量。
                     特殊键值:IPC_PRIVATE, 该信号量只允许创建者本身, 可用于父子进程间通信。
               nsems, 需要的信号量数目,一般取1
               sem_flags, 与共享内存的sem_flags类似。
                                  IPC_CREAT, 如果该信号量未存在,则创建该信号量
                                                     如果该信号量已存在,也不发送错误。
      返回值: 成功,则返回一个正数
                  失败,   返回返回-1
      

      2) 信号量的操作
      semop

      原型:int semop(int semid, struct sembuf *sops, unsigned nsops);
      功能:改变信号量的值,即对信号量执行P操作、或V操作。
      参数:semid, 信号量标识符, 即semget的返回值
      sops, 是一个数组,元素类型为struct sembuf

                        struct sembuf {
                             short  sem_num;  //信号量组中的编号(即指定对哪个信号量操作)
                                                        //semget实际是获取一组信号量
                                                        //如果只获取了一个信号量,则该成员取0
                             short  sem_op;     //   -1,  表示P操作
                                                        //   1,  表示V操作
                             short  sem_flg;     // SEM_UNDO : 如果进程在终止时,没有释放信号量
                                                 // 如果不设置指定标志,应该设置为0                                 则,自动释放该信号量                     
                        }        
      
             nsops, 表示第二个参数sops所表示的数组的大小,
                       即表示有几个struct sembuf
      

      返回值: 失败, 返回-1
      成功, 返回 0

      3) 信号量的控制
      semctl
      原型:int semctl(int semid, int sem_num, int cmd, …);
      功能:对信号量进行控制
      参数:semid, 信号量标识符
      sem_num, 信号量组中的编号,如果只有一个信号量,则取0
      cmd, SETVAL 把信号量初始化为指定的值,具体的值由第4个参数确定
      注意:只能对信号量初始化一次,
      如果在各进程中,分别对该信号量进行初始化,则可能导致错误!
      IPC_RMID 删除信号量
      参数4,
      类型为:union semun {
      int val; // SETVAL命令要设置的值
      struct semid_ds *buf;
      unsigned short *array;
      }
      注意:union semun类型要求自己定义
      有些Linux发行版在sys/sem.h中定义,有些发行版则没有定义。

                   可自定义如下:
                    -------------------------------------------------------------------------------------
                     #if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)                          
                      #else
                          union semun {
                              int val;                             
                              struct semid_ds *buf;    
                              unsigned short int *array; 
                              struct seminfo *__buf;  
                          };
                      #endif     
                      --------------------------------------------------------------------------------------            
      
    4. 实例
      实例1:不使用信号量,并发执行多个进程,观察对临界区的访问。
      main1.c

      实例2:使用信号量,并发执行多个进程,观察对临界区的访问。
      main2.c (对main1.c改进)

           使用信号量实现对文件操作的互斥访问。
           程序1,对test.txt写入学生记录信息10条
           程序2,对test.txt写入教师记录信息10条
           程序1和程序2并发执行
      
           main3/write_teacher.c
           main3/write_student.c
           main3/write.h
      
           注意:1)在临界区内异常退出时,一定要先释放信号量
                    2)信号量只初始化一次
      

    买票进程
    //信号量s,已经初始化为0

    P(s);
    if (count > 0) {
    printf(“sold NO. %d ”, count);
    }
    count–;
    V(s);

    //进程的互斥
    //操作原语

    ./a.out 1

    ./a.out

    1、 本地
    init

    服务器
    时间服务进程
    用户进程A

    ODU
    MODEM 
    CLI
    WEB
    
    CONTROL
    

    客户端

    1. 网络

    服务器
    客户端

    信号量的作用:
    1)进程之间的互斥
    2)进程之间的同步

    进程1
                向文件test.txt写入数据
    
    
    
    进程2
                从文件test.txt读取数据
    
  • 相关阅读:
    2-反向调试
    1-断点调试
    gdb基础用法
    protobuf学习手册(上)
    1024 科学计数法 (20 分)
    1023 组个最小数 (20 分)
    1018 锤子剪刀布 (20 分)
    1015 德才论 (25 分)
    1020 月饼 (25 分)
    1019 数字黑洞 (20 分)
  • 原文地址:https://www.cnblogs.com/Sico2Sico/p/5384207.html
Copyright © 2020-2023  润新知