zoukankan      html  css  js  c++  java
  • Linux下semaphore的使用 进程间互斥的一个好方法

    semaphore很类似windows下的kernel object,一旦创建,可以被多个进程使用,当然一个进程中多个线程也可以使用semaphore来互斥。谈到互斥,一般semaphore的值就是 1。man 7 sem_overview可以看到很多有用的信息,再结合sem_open, sem_wait, sem_post这些函数的man手册,就可以把程序编的七七八八了。

    Semaphore和pipe一样,也有有名的和无名的两种。无名的嘛,在父子进程间使用比较方便,有名的嘛,在不搭界的多进程中使用很方便。

    这里贴一段代码,代码最能说明问题,其他都参考manual就OK了。

    在Fix TI的一个bug的时候,做了这样的互斥。首先在ResourceManager中创建一个semaphore,因为ResourceManager以daemon程序的方式,一开始就会启动:

    Code: Select all
       /* Change umask temporarily to make sure the correct permission */
        old_mask = umask(0);
        alp_mmsem = sem_open(ALP_MMSEM_NAME, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, 1);
        if (alp_mmsem == SEM_FAILED) {
            fprintf(stderr, "ALP create mm semaphore failed. Name: %s, Reason: %s\n",
                    ALP_MMSEM_NAME, strerror(errno));
            unlink(RM_SERVER_IN);
            return 1;
        }
        umask(old_mask);



    用完释放:

    Code: Select all
       if (alp_mmsem != NULL) {
            sem_close(alp_mmsem);
            sem_unlink(ALP_MMSEM_NAME);
        }


    1. 使用umask将创建出来的文件权限要设置正确了。因为后续所有不是root的进程都要能读写这个有名semaphore才行。sem_open和 open很类似,创建出来的文件,权限是我们指定的权限,也就是上面代码中的:S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH 再与上 umask的非。就是:<我们设置的权限> & ~umask。所以这里我们将umask设成0,非一下就是全1,这样保证出来的文件就是我们设置的那个权限。Linux默认的umask是022,所以 如果要设置的权限是666的话,与上~022,出来的就是644了。umask的返回值是上次的umask值,所以这里代码里在设置完我们的文件权限后, 再把umask恢复回去,不影响后续的代码。
    2. 非常重要的是,sem_open的第一个参数,是这个有名sem的path,这里path不能写成/tmp/aaa.sem这样的格式,因为Linux 下,sem都是创建在/dev/shm目录下的(Linux的/dev/shm是一个tmpfs类型的特殊fs,就像/proc, /sys一样,用mount命令就可以看到),而且会加上sem.这样的prefix,所以,这里我们的ALP_MMSEM_NAME的值是 /alpmm,这样创建出来的文件就是/dev/shm/sem.alpmm了,千万不要写路径哦。名字可以以/打头,不以/打头也是可以的。
    3. 和windows的kernel object一样,sem也有counter,只有所有open了该sem的进程都sem_close了,该sem才会真正被内核销毁。使用sem_unlink就可以删掉该sem对应的文件。

    创 建好了,就可以使用了,和windows kernel object一样,使用也是调用sem_open首先得到一个sem的handle(当然这里flag就不能写O_CREAT了),然后sem_wait 就是将该sem的值减1,由于sem定义规定了sem的值不能小于0,所以如果sem_wait之后的sem的值小于1的话,sem_wait就会 block,直到有人增加了sem的值才会return,这样达到互斥的效果。sem_post就是给sem的值加1。

    Code: Select all
       if (alp_mmsem == NULL)  /* Avoid create semaphore multi times */
        {
            alp_mmsem = sem_open(ALP_MMSEM_NAME, O_RDWR);
            if (alp_mmsem == SEM_FAILED) {
                /* How can we do now? */
                fprintf(stderr, "ALP LCML open semaphore %s failed. Reason: %s\n",
                        ALP_MMSEM_NAME, strerror(errno));
                return OMX_ErrorUndefined;  /* FIXME, We should define our OMX ErrorCode here */
            }
        }

    ......

       if (sem_wait(alp_mmsem) == -1) {
            fprintf(stderr, "ALP LCML sem_wait failed. Reason: %s\n", strerror(errno));
            return OMX_ErrorUndefined;
        }

    ......

       if (sem_post(alp_mmsem) == -1) {
          fprintf(stderr, "ALP LCML sem_post failed, this is FATAL, maybe cause deadlock. Reason: %s\n", strerror(errno));
          return OMX_ErrorUndefined;
       }



    使用非常方便,记得用完之后sem_close。

    基本上就是这样了。不过注意使用无名semaphore的话,API和这些是不一样的,诸如有sem_init这样的API存在。所以如果使用无名sem的话,请参考linux manual。
  • 相关阅读:
    java 实现Queue
    java 实现stack
    为什么现货白银/现货原油的报价每个交易所都不一样?
    现货交易入门之常用术语
    现货操盘手精髓语录
    现货电子交易中实物交割的概念和作用?
    关于ios对rtsp格式的流媒体支持的一些官方说明
    ProgressBar的Indeterminate属性
    安卓适配问题
    推送原理
  • 原文地址:https://www.cnblogs.com/super119/p/1996116.html
Copyright © 2011-2022 走看看