Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

信号量

  • 引用

    #include <semaphore.h>
    
    
  • 全局声明

    static sem_t sem
    
  • 初始化信号量

    int sem_init(sem_t* sem, int pshared, unsigned int value);
    
    • sem 将要保存信号量的变量地址值
    • pshared 决定由几个进程共享
      • 传递0时,只允许1个进程内部使用
    • value 新创建的信号量的初始值
  • 请求信号量(减1)

    int sem_wait(sem_t* sem);
    
    • 进入临界区前调用
    • 调用后,如果信号量为0,则进入阻塞状态,否则减1后返回
  • 归还信号量(加1)

    int sem_post(sem_t* sem);
    
    • 离开临界区后调用
    • 调用后,加1返回,如果此时有阻塞的线程,则可以重新减回0并跳出阻塞状态
  • 销毁信号量

    int sem_destroy(sem_t* sem);
    
  • 信号量的两种用途

    • 同时访问互斥——只需1个互斥量

      sem_wait(&sem);
      //临界区
      sem_post(&sem);
      
    • 控制访问顺序——需要2个互斥量,一个为1,一个为0

      #include <stdio.h>
      #include <pthread.h>
      #include <semaphore.h>
      
      void* read(void*arg);
      void* accu(void* arg);
      static sem_t sem_one;
      static sem_t sem_two;
      static int num;
      
      int main(int argc, char* argv[]) {
          pthread_t id_t1, id_t2;
          sem_init(&sem_one, 0, 0);
          sem_init(&sem_two, 0, 1);
      
          pthread_create(&id_t1, NULL, read, NULL);
          pthread_create(&id_t2, NULL, accu, NULL);
      
          pthread_join(id_t1, NULL);
          pthread_join(id_t2, NULL);
      
          sem_destroy(&sem_one);
          sem_destroy(&sem_two);
          return 0;
      }
      
      void* read(void*arg) {
          for (int i = 0; i < 5; i++) {
              puts("Input num: ");
              sem_wait(&sem_two);
              scanf("%d", &num);
              sem_post(&sem_one);
          }
          return NULL;
      }
      void* accu(void* arg) {
          int sum = 0;
          for (int i = 0; i < 5; i++) {
              sem_wait(&sem_one);
              sum += num;
              sem_post(&sem_two);
          }
          printf("Result: %d \n", sum);
          return NULL;
      }
      
      • 解释
        • 初始 —— 1号信号量为0,2号信号量为1
        • read函数先sem_wait请求2号信号量,然后等待输入,只有输入了才会sem_post归还1号互斥量,然后下一次循环堵住
        • accu函数堵在sem_wait请求1号互斥量,只有read输入完,才会继续往下执行,追加到sum,并sem_post归还2号信号量,这样上面read的下一次循环才能开始
        • 这样循环往复,就能实现两个函数按照“输入一次,追加一次”的顺序执行
      • 编译时注意,要加上-lpthread
        gcc semaphore.c -o semaphore -lpthread
        
        • 要在Linux下才能成功
        • 在macOS下会提示init和destroy函数是deperated
          • 虽然能执行,但Result却是立刻输出了
      • 输出——需要陆续输入数字,最后才会返回结果
        Input num: 
        1
        Input num: 
        2
        Input num: 
        3
        Input num: 
        4
        Input num: 
        5
        Result: 15