Linux下用semaphore來做進程間互斥

來源:互聯網
上載者:User

semaphore很類似windows下的kernel object,一旦建立,可以被多個進程使用,當然一個進程中多個線程也可以使用semaphore來互斥。談到互斥,一般semaphore的值就是1。man 7 sem_overview可以看到很多有用的資訊。

Semaphore和pipe一樣,也有有名的和無名的兩種。無名的嘛,在父子進程間使用比較方便,有名的嘛,在"不搭界"的多進程中使用很方便。

這裡貼一段代碼,代碼最能說明問題,其他都參考manual就OK了。

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

............

    /* Release after used */
    if (super_mmsem != NULL) {
        sem_close(super_mmsem);
        sem_unlink("/supermm");
    }

 

 1. 使用umask將建立出來的檔案許可權要設定正確了。因為後續所有不是root的進程都要能讀寫這個有名semaphore才行。sem_open和open很類似,建立出來的檔案,許可權是我們指定的許可權,也就是上面代碼中的:S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH 再與上 umask的非。就是:<我們設定的許可權> & ~umask。這就是為什麼調用umask(0)的原因。Linux預設的umask是022,所以如果要設定的許可權是666的話,與上~022,出來的就是644了。

2. sem_open的第一個參數需要注意,是這個有名sem的path,這裡path不能寫成/tmp/aaa.sem這樣的格式,因為Linux下,sem都是建立在/dev/shm目錄下的(Linux的/dev/shm是一個tmpfs類型的特殊fs,就像/proc, /sys一樣,用mount命令就可以看到),而且會加上sem.這樣的prefix,所以,這裡代碼裡的值是/supermm,這樣建立出來的檔案就是/dev/shm/sem.supermm了,千萬不要寫路徑。名字可以以/打頭,不以/打頭也是可以的。
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。

    if (super_mmsem == NULL)  /* Avoid create semaphore multi times */
    {
        super_mmsem = sem_open("/supermm", O_RDWR);
        if (super_mmsem == SEM_FAILED) {
            /* How can we do now? */
            fprintf(stderr, "Open semaphore %s failed. Reason: %s\n", "/supermm", strerror(errno));
            return 1;
        }
    }

......

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

......

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

 

 使用非常方便,記得用完之後sem_close。

That's it。不過注意使用無名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.