Linux学习笔记26——信号量

系统 2074 0

一 信号量的基本概念

  信号量:它是一个特殊变量,只允许对它进行等待和发送信号这两种操作。
  假设有一个信号量变量sv
  P(sv):用于等待,如果sv的值大于零,就给它减去1,如果它的值等于零,就挂起该进程的执行。
  V(sv):用于发送信号,如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而被挂起,就给它加1

二 信号量的相关函数

      
        #include <sys/sem.h>
      
      
//semctl函数的作用是用来直接控制信号量信息 int semctl( int sem_id,             //由semget返回的信号量标识符
int sem_num,            //是信号量编号,当需要用到成组的信号量时,就要用到这个参数,它一般取值为0,表示这是第一个也是唯一的信号量
int command,            //是将要采取的动作
       ...                 //它将会是一个union semun结构
      );
//semget函数的作用是创建一个新信号量或取得一个已有信号量的键。
int semget(key_t key, //key是整数值,不相关的进程可以通过它访问同一个信号量
       int
num_sems,           //指定需要的信号量数目,几乎总是取值为1

int sem_flags           //是一组标志,与open函数的标志非常相似
      );                  //在成功时返回一个正数(非零)值,它就是其他信号量函数将用到的信号量标识符,如果失败,则返回-1
//semop函数用于改变信号量的值
int semop( int sem_id,            //由semget返回的信号量标识符
struct sembuf *sem_ops,    //指向一个 sembuf 结构数组的指针
      size_t num_sem_ops //信号操作结构的数量,恒大于或等于1
     );

semun包含于semun.h头文件中

      
        
          union semun{ 
        
        
          int
        
        
           val;          
          
            //SETVAL所设置的信号量集中的一个信号量的值 
          
        
        
          struct
        
         semid_ds *
        
          buf; 
          
             //IPC_STAT,IPC_SET存储的数据
          
           unsigned 
        
        
          short
        
         *
        
          array; 
          
             //GETALL, SETALL返回值的数组
          
           }
        
      
    

  semop函数中的sembuf结构体

      
        
          struct
        
        
           sembuf{ 
        
        
          short
        
        
           sem_num;  
          
            //信号量编号,除非需要使用一组信号量,否则它的取值一般为0 
          
        
        
          short
        
         sem_op;   
        
          //是信号量在一次操作中需要改变的数值,通常只会用到两个值,一个是-1,也就是P操作,它等待信号量变为己用;一个是+1,也就是V操作,它发送信号表示信号量现在已可用 
        
        
          short
        
        
           sem_flg;  
          
            //通常设置为SEM_UNDO,它将使得操作系统跟踪当前进程对这个信号量的修改情况
          
           }
        
      
    

  semctl中第三个参数command取值如下:

    ·IPC_STAT:读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
    ·IPC_SET:设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
    ·IPC_RMID:将信号量集从内存中删除。
    ·GETALL:用于读取信号量集中的所有信号量的值。
    ·GETNCNT:返回正在等待资源的进程数目。
    ·GETPID:返回最后一个执行semop操作的进程的PID。
    ·GETVAL:返回信号量集中的一个单个的信号量的值。
    ·GETZCNT:返回这在等待完全空闲的资源的进程数目。
    ·SETALL:设置信号量集中的所有的信号量的值。
    ·SETVAL:设置信号量集中的一个单独的信号量的值。


三 例子

      
        #include <unistd.h>
        
           #include 
        
        <stdlib.h>
        
           #include 
        
        <stdio.h>
        
           #include 
        
        <sys/sem.h>
        
           #include 
        
        
          "
        
        
          semun.h
        
        
          "
        
        
          static
        
        
          int
        
         set_semvalue(
        
          void
        
        
          ); 
        
        
          static
        
        
          void
        
         del_semvalue(
        
          void
        
        
          ); 
        
        
          static
        
        
          int
        
         semaphore_p(
        
          void
        
        
          ); 
        
        
          static
        
        
          int
        
         semaphore_v(
        
          void
        
        
          ); 
        
        
          static
        
        
          int
        
        
           sem_id; 
        
        
          int
        
         main(
        
          int
        
         argc,
        
          char
        
         *
        
          argv[]){ 
        
        
          int
        
        
           i; 
        
        
          int
        
        
           pause_time; 
        
        
          char
        
         op_char=
        
          '
        
        
          0
        
        
          '
        
        
          ; srand((unsigned 
        
        
          int
        
        
          )getpid()); sem_id
        
        =semget((key_t)
        
          1234
        
        ,
        
          1
        
        ,
        
          0666
        
        |
        
          IPC_CREAT); 
        
        
          if
        
        (argc>
        
          1
        
        
          ){ 
        
        
          if
        
        (!
        
          set_semvalue()){ fprintf(stderr,
        
        
          "
        
        
          Failed to initialize semaphore\n
        
        
          "
        
        
          ); exit(EXIT_FAILURE); } op_char
        
        =
        
          '
        
        
          X
        
        
          '
        
        
          ; sleep(
        
        
          2
        
        
          ); } 
        
        
          //
        
        
          进入和离开临界区域10次,在每次循环的开始,首先调用semaphore函数,它在程序进入临界区域时设置信号量以等待进入
        
        
          for
        
        (i=
        
          0
        
        ;i<
        
          10
        
        ;i++
        
          ){ 
        
        
          if
        
        (!
        
          semaphore_p()){ exit(EXIT_FAILURE); } printf(
        
        
          "
        
        
          %c
        
        
          "
        
        
          ,op_char); fflush(stdout); pause_time
        
        =rand()%
        
          3
        
        
          ; sleep(pause_time); printf(
        
        
          "
        
        
          %c
        
        
          "
        
        
          ,op_char); fflush(stdout); 
        
        
          //
        
        
          临界区域之后,调用semaphore_v来将信号量设置为可用,然后等待一段随机时间,再进入下一次循环。在整个循环语句执行完毕后,调用del_semvalue函数来清理代码
        
        
          if
        
        (!
        
          semaphore_v()){ exit(EXIT_FAILURE); } pause_time
        
        =rand()%
        
          2
        
        
          ; sleep(pause_time); } printf(
        
        
          "
        
        
          \n%d - finished\n
        
        
          "
        
        
          ,getpid()); 
        
        
          if
        
        (argc>
        
          1
        
        
          ){ sleep(
        
        
          5
        
        
          ); del_semvalue(); } exit(EXIT_SUCCESS); } 
        
        
          //
        
        
          函数set_semvalue通过将semct1调用的command参数设置为SETVAL来初始化信号量
        
        
          static
        
        
          int
        
         set_semvalue(
        
          void
        
        
          ){ union semun sem_union; sem_union.val
        
        =
        
          1
        
        
          ; 
        
        
          if
        
        (semctl(sem_id,
        
          0
        
        ,SETVAL,sem_union)==-
        
          1
        
        
          ){ 
        
        
          return
        
        
          0
        
        
          ; } 
        
        
          return
        
        
          1
        
        
          ; } 
        
        
          static
        
        
          void
        
         del_semvalue(
        
          void
        
        
          ){ union semun sem_union; 
        
        
          if
        
        (semctl(sem_id,
        
          0
        
        ,IPC_RMID,sem_union)==-
        
          1
        
        
          ){ fprintf(stderr,
        
        
          "
        
        
          Failed to delete semaphore
        
        
          "
        
        
          ); } } 
        
        
          //
        
        
          semaphore_p对信号量做减1操作(等待)
        
        
          static
        
        
          int
        
         semaphore_p(
        
          void
        
        
          ){ 
        
        
          struct
        
        
           sembuf sem_b; sem_b.sem_num
        
        =
        
          0
        
        
          ; sem_b.sem_op
        
        =-
        
          1
        
        
          ; sem_b.sem_flg
        
        =
        
          SEM_UNDO; 
        
        
          if
        
        (semop(sem_id,&sem_b,
        
          1
        
        )==-
        
          1
        
        
          ){ fprintf(stderr,
        
        
          "
        
        
          semaphore_p failed\n
        
        
          "
        
        
          ); 
        
        
          return
        
        
          0
        
        
          ; } 
        
        
          return
        
        
          1
        
        
          ; } 
        
        
          //
        
        
          semaphore_v将sembuf结构中的sem_op设置为1,释放操作
        
        
          static
        
        
          int
        
         semaphore_v(
        
          void
        
        
          ){ 
        
        
          struct
        
        
           sembuf sem_b; sem_b.sem_num
        
        =
        
          0
        
        
          ; sem_b.sem_op
        
        =
        
          1
        
        
          ; sem_b.sem_flg
        
        =
        
          SEM_UNDO; 
        
        
          if
        
        (semop(sem_id,&sem_b,
        
          1
        
        )==-
        
          1
        
        
          ){ fprintf(stderr,
        
        
          "
        
        
          semaphore_v failed\n
        
        
          "
        
        
          ); 
        
        
          return
        
        
          0
        
        
          ; } 
        
        
          return
        
        
          1
        
        
          ; }
        
      
    

 

Linux学习笔记26——信号量


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论