zoukankan      html  css  js  c++  java
  • Linux进程间通信---信号量

    • 信号量是一个计数器,通常在内核中实现,用于多个进程对共享数据对象的同步访问。使用信号量的头文件是#include <sys/sem.h>
    • 信号量的使用规则:
      • 若信号量为正,则进程可使用该资源。
      • 若信号量为0,则进程阻塞等待,并将进程插入等待队列,直到该信号量的值大于0从等待队列中执行进程请求。
      • 加锁操作:如果信号量大于0,则信号量-1;如果信号量为0,则挂起该进程,并将这个进程插入等待队列。
      • 解锁操作:如果等待队列中有进程则唤醒该进程,让它恢复运行;否则,信号量+1。
    • Linux下使用信号量的常用函数:
      • semget(key, num_sems, sem_flags):创建新的信号量或取得已有的信号量,key表示信号量的键值,不相关进程使用同一个key来访问同一个信号量,num_sems表示信号量个数(一般为1),sem_flags表示信号量访问权限,用IPC_CREAT与权限位与可保证信号量不存在时新建一个。函数返回一个int类型的数值,表示信号量的标识符。
      • semop(sem_id, sem_opa, num_sem_ops):改变信号量的值,改变操作在sem_opa中,sem_opa是sumbuf结构体对象,使用方法如下:
        struct sembuf
        {  
           short sem_num;   //除非使用一组信号量,否则它为0  
           short sem_op;    //信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P操作(加锁);一个是+1,即V操作(解锁)
           short sem_flg;   //通常为SEM_UNDO,使操作系统跟踪信号,并在进程没有释放该信号量而终止时,操作系统释放信号量  
        };
      • semctl(sem_id, sem_num, command, semun):控制信号量。commond中有:SETVAL初始化信号量为一个值,该值再semun结构体的val字段;IPC_RMID用于删除一个无需继续使用的信号量。
    • 信号量的使用实例,同时开两个进程,每个进程中都用信号量同步临界区,在临界区中向屏幕打印字符:
      #include <unistd.h>
      #include <sys/types.h>
      #include <sys/stat.h>
      #include <fcntl.h>
      #include <stdlib.h>
      #include <stdio.h>
      #include <string.h>
      #include <sys/sem.h>
       
      union semun
      {
          int val;
          struct semid_ds *buf;
          unsigned short *arry;
      };
       
      static int sem_id = 0;
      static int set_semvalue();
      static void del_semvalue();
      static int semaphore_p();
      static int semaphore_v();
       
      int main(int argc, char *argv[])
      {
          char message = 'X';
          int i = 0;
       
          //创建信号量
          sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT);
       
          if(argc > 1)
          {
              //程序第一次被调用,初始化信号量
              if(!set_semvalue())
              {
                  fprintf(stderr, "Failed to initialize semaphore
      ");
                  exit(EXIT_FAILURE);
              }
              //设置要输出到屏幕中的信息,即其参数的第一个字符
              message = argv[1][0];
              sleep(2);
          }
          for(i = 0; i < 10; ++i)
          {
              //进入临界区
              if(!semaphore_p())
                  exit(EXIT_FAILURE);
              //向屏幕中输出数据
              printf("%c", message);
              //清理缓冲区,然后休眠随机时间
              fflush(stdout);
              //离开临界区,休眠随机时间后继续循环
              if(!semaphore_v())
                  exit(EXIT_FAILURE);
              sleep(2);
          }
       
          sleep(3);
          printf("
      %d - finished
      ", getpid());
       
          if(argc > 1)
          {
              //如果程序是第一次被调用,则在退出前删除信号量
              sleep(3);
              del_semvalue();
          }
          exit(EXIT_SUCCESS);
      }
       
      static int set_semvalue()
      {
          //用于初始化信号量,在sem_union的val字段中设置信号量初值。使用信号量之前必须先初始化!
          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()
      {
          //删除信号量
          union semun sem_union;
          if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
              printf("Failed to delete semaphore
      ");
      }
       
      static int semaphore_p()
      {
          //对信号量做减1操作,即加锁 P(sv)
          struct sembuf sem_b;
          sem_b.sem_num = 0;
          sem_b.sem_op = -1;   //P()
          sem_b.sem_flg = SEM_UNDO;
          if(semop(sem_id, &sem_b, 1) == -1)
          {
              printf("semaphore_p failed
      ");
              return 0;
          }
          return 1;
      }
       
      static int semaphore_v()
      {
          //这是一个释放操作,它使信号量变为可用,即解锁 V(sv)
          struct sembuf sem_b;
          sem_b.sem_num = 0;
          sem_b.sem_op = 1;   //V()
          sem_b.sem_flg = SEM_UNDO;
          if(semop(sem_id, &sem_b, 1) == -1)
          {
              printf("semaphore_v failed
      ");
              return 0;
          }
          return 1;
      }
          ps:以上代码参考自https://blog.csdn.net/ljianhui/article/details/10243617,运行结果如下:
                 
  • 相关阅读:
    Kafka
    js操作json
    Javascript的console.log()用法
    js中的instanceof运算符
    JS阻止事件冒泡的3种方法之间的不同
    js string to date
    JavaScript RegExp.$1
    JS正则表达式大全
    js data日期初始化的5种方法
    javascript和jquey的自定义事件小结
  • 原文地址:https://www.cnblogs.com/ladawn/p/8870014.html
Copyright © 2011-2022 走看看