Linux下semaphore的使用 — 進程間互斥的一個好方法

來源:互聯網
上載者:User
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。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.