Linux 訊號量互斥編程

來源:互聯網
上載者:User

標籤:

所謂訊號量,其實就是一個數字。核心給這個數字賦予一定的含義,讓它等於不同的值時所表示的意義不同。這樣就可以用它來標示某種資源是否正被使用。訊號的分類其實挺多的,主要還是二值和計數器。這裡討論二值

現在有個檔案,有兩個進程要同時訪問它。進程A 要往裡面寫入 "Math class is cancel",進程B 要往裡面寫入“English test”。正常情況下這兩個資訊會被完整的寫入檔案中。但是如果進程A寫到"Math class" 就暫停,接著B進程就開始寫“English test”,最後進程A繼續寫剩下的“is cancel ”,那檔案最後的結果就是“Math class English test is cancel”。結果顯然錯的離譜。究其錯誤的原因其實很簡單,兩個進程在同時公用一個資源但是又沒有一種機制來控制訪問的先後順序。因為Linux 是一個多任務的系統,這中資源被多個任務同時訪問的情況是非常普遍的。我們需要一種機制來控制資源能夠被有序的訪問。訊號量就是一種實現。

訊號量互斥的實現機制簡單描述如下:

讓兩個進程在真正寫入資料之前先測試訊號量sig。當進程A要寫入檔案時,它先測試訊號量sig,如果訊號量sig 等於1,表示這個檔案沒有其他進程再使用,那麼它就將這個訊號量減1 讓它等於0,接著直接寫資料到這個檔案。但是當進程B測試訊號量sig 時發現它等於0 ,表示有進程在使用它,那麼核心就讓進程B掛起,當訊號量的值被置為1時它才能繼續執行寫入操作。、

描述完訊號量的機制就可以討論Linux核心對於訊號量的實現。

事實上linux核心關於訊號量的介面還是很簡潔的。就三個函數:

int semget(key_t key, int num_sems, int sem_flags);
int semop(int semid, struct sembuf *sops, size_t ops_num);

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

semget函數

這個函數的功能是 建立/開啟一個訊號量集合,所謂集合其實就相當於數組。一個進程可能與多種資源相關聯,可以用多個訊號量來控制這些資源的訪問。可見Linux 核心提供的訊號量集合的概念是合理的。下面討論它的參數和傳回值:

傳回值很簡單,就是一個整型數----訊號量標識符,標識符是核心為每個開啟了的訊號量集合而分配的,訪問某個訊號量集合就得靠它了(類比檔案編程裡的檔案描述符)。key參數:索引值。核心為所有的訊號量集合維護了不同的索引值,不管訊號量集合是否被開啟,這個索引值都存在。索引值其實就相當於檔案名稱,但是索引值是個整數,它可以自由指定,只是自由指定容易使得不同的訊號量擁有相同的索引值。因此核心提供了一個函數來分配索引值:key_t ftok(const char *pathname, int proj_num);這個函數合成索引值的機制簡單描述下:

根據檔案名稱pathname在核心中表示的數字以及proj_num共同合成一個索引值key 並返回給調用者。num_sems參數:表明這個訊號量集合的訊號量個數。sem_flags參數:開啟的標誌,可以取值IPC_CREAT。當函數調用中有這個參數,並且索引值指定的訊號量集合不存在,那麼這個函數就建立一個key 表示的訊號量集合。

semop 函數

semop 函數用來訊號量集合。事實上訊號量集合的操作很簡單,無非就是將訊號量加一或者減一,來分別表示釋放或者擷取訊號量。傳回值除了表示操作的成敗,沒有什麼意義。semid 參數:開啟的訊號量集合的標識符,從semget 返回。ops_num 參數:表示這個操作函數操作多少個訊號量,因為訊號量集合可能有多個訊號量。 ops執行的結構體定義如下:

struct  sembuf

{

      unsigned short   sem_num;//表明這個訊號量在訊號量集合中是哪一個

      short       sem_op;     //表明操作類型    整數表明+1, 負數表明-1。事實上擷取訊號量和釋放                                                    訊號量就是在這裡區別

      short        sem_flg;     

}

semctl 函數

semctl函數是在訊號量上執行的多種操作。semid參數:表明要操作的訊號量集合的標識符。semnum參數:表明要操作的訊號量個數。command參數:表明要執行的命令。當我們要給訊號量賦初值時可以令command == SETVAL,然後在省略參數給出要賦的值。

函數說明完了,下面給出一個簡單的執行個體測試一下訊號量互斥編程:

進程A:

#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <sys/ipc.h>#include <sys/sem.h>int main(){    int fd = 0;    key_t key;    int semid;    struct sembuf sops;       //建立並開啟訊號量    key = ftok("/home",1);    semid = semget(key,1,IPC_CREAT);        semctl(semid,0,SETVAL,1);    /* 0.開啟公示欄*/    fd = open("./board.txt",O_RDWR|O_APPEND);        //擷取訊號量    sops.sem_num = 0;    sops.sem_op = -1;    semop(semid,&sops,1);        /* 1. 寫入“數學課” */    write(fd,"Math class",11);            /* 2. 暫停 */    sleep(10);        /* 3. 寫入“取消”*/    write(fd,"is cancel",10);        //釋放訊號量    sops.sem_num = 0;    sops.sem_op = 1;    semop(semid,&sops,1);            /* 4. 關閉公示欄 */    close(fd);        return 0;}
View Code

進程B:

#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <sys/ipc.h>#include <sys/sem.h>int main(){    int fd = 0;    key_t key;    int semid;    struct sembuf sops;            /* 0.開啟公示欄 */    fd = open("./board.txt",O_RDWR|O_APPEND);        //開啟訊號量    key = ftok("/home",1);    semid = semget(key,1,IPC_CREAT);        //擷取訊號量    sops.sem_num = 0;    sops.sem_op = -1;    semop(semid,&sops,1);        /* 1. 寫入“英語課” */    write(fd,"Enclish exam",13);            //釋放訊號量    sops.sem_num = 0;    sops.sem_op = 1;    semop(semid,&sops,1);              /* 2. 關閉公示欄 */    close(fd);        return 0;}
View Code

 

Linux 訊號量互斥編程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.