• 进程间通信-信号量


    Linux内核信号量集用结构体semid_ds结构体表示,semid_ds的结构体定义如下:

    /* Data structure describing a set of semaphores.  */
    struct semid_ds
    {
      struct ipc_perm sem_perm;        /* operation permission struct */
      __time_t sem_otime;            /* last semop() time */
      __syscall_ulong_t __glibc_reserved1;
      __time_t sem_ctime;            /* last time changed by semctl() */
      __syscall_ulong_t __glibc_reserved2;
      __syscall_ulong_t sem_nsems;        /* number of semaphores in set */
      __syscall_ulong_t __glibc_reserved3;
      __syscall_ulong_t __glibc_reserved4;
    };

    每个信号量则描述为:

    struct sem{
           int    semval ;
           int    sempid ;     
           int    semcnt ;
           int    semzcnt;
    };  

    信号量的基本操作包括创建信号量、信号量的值操作、获取或设置信号量属性,对应的相关函数的分别是semget、semop、semctl。

    1.创建信号量集

    semget函数用于创建信号量,如果参数key指定的信号量集已经存在,则就返回该信号量集。

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    int semget(key_t key, int nsems, int flag);

    key:一个整数类型的键值,用来命名某个特定的信号量集。

    nsems:指定打开或者新创建的信号量集包含的信号量数目。

    falg:9个位的权限标志。

    返回值:成功返回信号量集描述字,否则返回-1。

    2.信号量值操作

    信号量本质上是一个计数器,进程可以使用函数semop来增加或者减少信号量值,以表示释放或者申请共享资源。

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    int semop(int sem_id, struct sembuf * sops, unsigned int nsops);

    sem_id:semget函数返回的信号量集描述字。

    nsops:本次操作的信号量数目,也是sops指向的数组的大小。

    sops:指向一个类型为sembuf的结构体数组。

    sembuf结构体:

    /* Structure used for argument to `semop' to describe operations.  */
    struct sembuf
    {
      unsigned short int sem_num;    /* semaphore number */
      short int sem_op;        /* semaphore operation */
      short int sem_flg;        /* operation flag */
    };

    如果sem_op为负数,就从信号量值中减去sem_op的绝对值,表示进程获取资源;如果sem_op为正数,就把它加到信号量上,表示归还资源;如果sem_op为0,则调用进程睡眠,直到信号量值为0。sem_flag一般设置为0。

    3.获取或者设置信号量属性

    系统中的每个信号量集都对应一个struct sem_ds结构体,该结构体记录信号量集的各种信息,存放于内核空间。为了设置、获取信号量集的各种信息及属性,在用户空间中有一个联合体union semnu与之对应。

    union semun {
        int              val;    /* Value for SETVAL */
        struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
        unsigned short  *array;  /* Array for GETALL, SETALL */
        struct seminfo  *__buf;  /* Buffer for IPC_INF    (Linux-specific) */
    };

    信号量属性操作的函数原型:

    #include <linux/sem.h>
    int semctl(int semid, int semnum, int cmd, union semun arg);

    semid:信号量集描述字。

    semnum:待操作的信号量在信号集semid中的索引。

    cmd:指定具体的操作类型,常见的操作有:

      SETVAL:设置semnum所代表信号量的值为arg.val。

      SETALL:通过arg.val更新所有信号量的值。

      IPC_RMID:从内核主存中删除信号量集。

      GETVAL:返回semnum所代表信号量的值。

    使用信号量创建自定义P/V操作函数库

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    
    
    int createsem(key_t key){
        return semget(key,1,IPC_CREAT|0666);
    }
    
    
    int getsem(key_t key){
        return semget(key,1,0666);
    }
    
    
    
    union semun {
        int              val;    /* Value for SETVAL */
        struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
        unsigned short  *array;  /* Array for GETALL, SETALL */
        struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                               (Linux-specific) */
    };
    
    
    
    
    int initsem(int semid,int initval){
        union semun arg;
        arg.val = initval;
        return semctl(semid,0,SETVAL,arg);
    }
    
    
    int P(int semid){
        struct sembuf operation[1];
        operation[0].sem_num = 0;
        operation[0].sem_op = -1;
        return semop(semid,operation,1);
    }
    
    
    int V(int semid){
        struct sembuf operation[1];
        operation[0].sem_num = 0;
        operation[0].sem_op = 1;
        return semop(semid,operation,1);
    }
    int delsem(int semid){
        union semun arg;
        semctl(semid,0,IPC_RMID,arg);
    }
    
    
    int main(int argc,char * argv[]){
        int semid = createsem(0x123456);
        int seccess =  initsem(semid,1);
        printf("semid:%d
    ",semid);
        printf("seccess:%d
    ",seccess);
    
    
    
    
       // int v = V(semid);
       // printf("v:%d
    ",v);
    
    
        int p = P(semid);
        printf("p:%d
    ",p);
    
    
        int close =  delsem(semid);
        printf("close:%d
    ",close);
        return 0;
    } 
  • 相关阅读:
    HDU 4287 Intelligent IME 第37届ACM/ICPC天津赛区网络赛1010题 (水题)
    HDU 4267 A Simple Problem with Integers 第37届ACM/ICPC长春赛区网络赛1001题 (树状数组)
    HDU 4277 USACO ORZ 第37届ACM/ICPC长春赛区网络赛1011题(搜索)
    HDU 4099 Revenge of Fibonacci(字典树)
    HDU 2802 F(N)(简单题,找循环解)
    HDU 4282 A very hard mathematic problem 第37届ACM/ICPC长春赛区网络赛1005题 (暴力)
    HDU 4268 Alice and Bob 第37届ACM/ICPC长春赛区网络赛1002题 (贪心+multiset)
    HDU 3501 Calculation 2(欧拉函数的引申)
    HDU 4278 Faulty Odometer 第37届ACM/ICPC天津赛区网络赛1001题 (简单水题)
    HDU 4279 Number 第37届ACM/ICPC天津赛区网络赛1002题 (简单规律题)
  • 原文地址:https://www.cnblogs.com/iuyy/p/13665796.html
Copyright © 2020-2023  润新知