zoukankan      html  css  js  c++  java
  • linux ipc信号量

    ipcs 命令,可以看到当前系统上的共享资源实例

    ipcrm 命令,可以删除一个共享资源实例

    linux 操作信号量的函数有三个:semget, semop, semctl

    semget 声明为:

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

    key 是一个键值,用来标识一个全局唯一的信号量集。要通过信号量通信的进程需要使用相同的键值来获取该信号量。

    nsems 表示要创建/获取的信号量集中信号量的数目。如果是创建信号量,这个值必须指定。如果是获取已经存在的信号量,可以把它设置成0.

    semflg 指定一组标志。它的低端9个比特是该信号量的权限。相当于文件操作权限,类似open函数的mode参数。而且,它还可以和IPC_CREAT标志按位“或”运算来创建新的信号量集。

    成功返回一个正整数,它是信号量集的标识符;失败返回-1,并设置errno

    semop 系统调用改变信号量的值,即执行P、V操作:

    int semop(int semid, struct sembuf *sops, size_t nsops);

    semid 是由 semget 返回的信号量集标识符,用来指定被操作的目标信号量集。

    sops 是 struct sembug 结构体,定义为:

    /* 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_num 是信号量集的编号,0表示第一个信号量。

    sem_op 指定操作类型,可选值为正整数、0、负整数。

    sem_flg 可选值是 IPC_NOWAIT, SEM_UNDO。IPC_NOWAIT指,无论信号量集操作是否成功,semop调用都立刻返回。SEM_UNDO含义是,当进程退出时,取消正在进行的semop操作

    nsops参数指定要执行的操作个数,即sops数组中元素的个数。semop对数组sops中的每个元素按照数组顺序依次执行操作,并且这个过程是原子操作。

    semop成功返回0,失败返回-1并设置errno。失败的时候,sops数组中指定的所有操作都不执行。

    semctl用来对信号量进行直接操作:

    int semctl(int semid, int semnum, int cmd, ...);

    semid 是semget调用返回的信号量集标识符。semnum指定被操作的信号量在信号量集中的编号。cmd指定要执行的命令。有的命令需要传入第4个参数,这个参数类型由用户定义,但是,内核给出了它的格式,而且,必须是这个格式:

               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) */
               };

    cmd 的值比较多,不列举了,可以看manpage,其中,

    IPC_STAT 将信号量集关联的内核数据结构复制到semun.buf中,

    GETVAL 获取信号量的semval的值

    SETVAL 将信号量的semval值设置为semun.val

    IPC_RMID 立即移除信号量集,唤醒所有等待信号量集的进程

    该函数返回值根据cmd不同而不同。失败返回-1,并设置errno

     

    semget函数第一个参数key可以设置为 IPC_PRIVATE(值为0),这样,无论信号量是否存在,都会创建一个新的信号量

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <unistd.h>
    #include <sys/wait.h>
    #include <sys/sem.h>
    
    
    //这个联合体需要手动定义
    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) */
    };
    
    void ErrExit(const char* reason)
    {
        fprintf(stderr, "%s: %d, %s
    ", reason, errno, strerror(errno));
        exit(1);
    }
    
    int initsem(int key = 0)
    {
        int semid = -1;
        if (-1 == (semid = semget(key, 1, 0666 | IPC_CREAT)))
        {
            ErrExit("semget");
        }
    
        // 信号量初始值为1
        union semun sem_un;
        sem_un.val = 1;
        if (-1 == semctl(semid, 0, SETVAL, sem_un))
        {
            ErrExit("semctl");
        }
    
        return semid;
    }
    
    void destroysem(int semid)
    {
        if (-1 == semctl(semid, 0, IPC_RMID))
        {
            ErrExit("semctl del");
        }
    }
    
    // -1 为 p 操作
    void P(int semid)
    {
        struct sembuf op;
        op.sem_num = 0;
        op.sem_op = -1;
        op.sem_flg = SEM_UNDO;
        if (-1 == semop(semid, &op, 1))
        {
            ErrExit("semop p");
        }
    }
    
    // 1 为 v 操作
    void V(int semid)
    {
        struct sembuf op;
        op.sem_num = 0;
        op.sem_op = 1;
        op.sem_flg = SEM_UNDO;
        if (-1 == semop(semid, &op, 1))
        {
            ErrExit("semop v");
        }
    }
    
    int main(int argc, char const *argv[])
    {
        int semid = initsem();
        pid_t pid = fork();
    
        if (pid > 0)
        {
            P(semid);
            printf("in parent process...
    ");
            sleep(1);
            V(semid);
    
            waitpid(pid, NULL, 0);
            // 删除信号量集
            destroysem(semid);
        }
        else if (0 == pid)
        {
            P(semid);
            printf("in child process...
    ");
            sleep(1);
            V(semid);
        }
        else
        {
            ErrExit("fork");
        }
    
        return 0;
    }

     

  • 相关阅读:
    腾讯开放平台 手机QQ登录 错误码:110406 解决办法
    比较酷的安卓软件
    Top 10 Methods for Java Arrays
    Feathers UI 性能优化
    Starling中通过PivotX 和 PivotY 修改原点
    Adobe AIR 中为不同尺寸和分辨率屏幕适配
    Feathers组件的宽度或高度属性,为什么我得到的值是0
    "Type Coercion failed" Error in FlashBuilder 4.7
    正则表达式中的特殊字符
    单体内置对象 Global 和 Math
  • 原文地址:https://www.cnblogs.com/zuofaqi/p/9643787.html
Copyright © 2011-2022 走看看