zoukankan      html  css  js  c++  java
  • Linux学习笔记26——信号量

    一 信号量的基本概念

      信号量:它是一个特殊变量,只允许对它进行等待和发送信号这两种操作。
      假设有一个信号量变量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
    ");
                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("
    %d - finished
    ",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
    ");
            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
    ");
            return 0;
        }
        return 1;
    }
  • 相关阅读:
    ubuntu 14.04搭建PHP项目基本流程
    linux下 lvm 磁盘扩容
    LVM基本介绍与常用命令
    Linux LVM逻辑卷配置过程详解
    mysql 5.7中的用户权限分配相关解读!
    linux系统维护时的一些小技巧,包括系统挂载新磁盘的方法!可收藏!
    linux系统内存爆满的解决办法!~
    源、更新源时容易出现的问题解决方法
    NV显卡Ubuntu14.04更新软件导致登录死循环,不过可以进入tty模式
    一些要注意的地方
  • 原文地址:https://www.cnblogs.com/zjzsky/p/3521215.html
Copyright © 2011-2022 走看看