linux進程間信號量

Linux 提供的各種系統調用來實現一個具有兩種狀態的信號量(binary semaphore)。

分配釋放

和用於分配、釋放共享記憶體的 shmget 和 shmctl 類似,系統調用 semget 和 semctl 負責分配、釋放信號量。調用 semget 函式並傳遞如下參數:一個用於標識信號量組的鍵值,該組中包含的信號量數量和與 shmget 所需的相同的許可權位標識。該函式返回的是信號量組的標識符。您可以通過指定正確的鍵值來獲取一個已經存在的信號量的標識符;這種情況下,傳遞的信號量組的容量可以為0。

信號量會一直保存在系統中,甚至所有使用它們的進程都退出後也不會自動被銷毀。最後一個使用信號量的進程必須明確地刪除所使用的信號量組,來確保系統中不會有太多閒置的信號量組,從而導致無法創建新的信號量組。可以通過調用semctl來刪除信號量組。調用時的四個參數分別為信號量組的標識符,操作的信號量在組中的編號、常量IPC_RMID 和一個 union semun 類型的任意值(被忽略)。調用進程的有效用戶 id 必須與分配這個信號量組的用戶 id 相同(或者調用進程為 root 許可權亦可)。與共享記憶體不同,刪除一個信號量組會導致 Linux 立即釋放資源。

代碼 5.2 展示了用於分配和釋放一個二元信號量的函式。

代碼 5.2 (sem_all_deall.c)分配和釋放二元信號量

#include <sys/ipc.h>

#include <sys/sem.h>

#include <sys/types.h> /* 我們必須自己定義 semun 聯合類型。 */

union semun { int val; struct semid_ds *buf; unsigned short int *array; struct seminfo *__buf; };

/* 獲取一個二元信號量的標識符。如果需要則創建這個信號量 */

int binary_semaphore_allocation (key_t key, int sem_flags)

{

return semget (key, 1, sem_flags);

} /* 釋放二元信號量。所有用戶必須已經結束使用這個信號量。如果失敗,返回 -1 */

int binary_semaphore_deallocate (int semid)

{

union semun ignored_argument; return semctl (semid, 1, IPC_RMID, ignored_argument);

}

初始信號

分配與初始化信號量是兩個相互獨立的操作。以 0 為第二參數,以 SETALL 為第三個參數調用 semctl 可以對一個信號量組進行初始化。第四個參數是一個 semun 對象,且它的 array 欄位指向一個 unsigned short數組。數組中的每個值均用於初始化該組中的一個信號量。

代碼 5.3 展示了初始化一個二元信號量的函式。

代碼 5.3 (sem_init.c) 初始化一個二元信號量

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

/* 我們必須自己定義 union semun。*/

union semun

{

int val;

struct semid_ds *buf;

unsigned short int *array;

struct seminfo *__buf;

};

/* 將一個二元信號量初始化為 1。*/

int binary_semaphore_initialize (int semid)

{

union semun argument;

unsigned short values[1];

values[0] = 1;

argument.array = values;

return semctl (semid, 0, SETALL, argument);

}

等待投遞

每個信號量都具有一個非負的值,且信號量支持等待和投遞操作。系統調用 semop 實現了這兩個操作。它的第一個參數是信號量的標識符,第二個參數是一個包含 struct sembuf 類型元素的數組;這些元素指明了您希望執行的操作。第三個參數是這個數組的長度。結構體sembuf中包含如下欄位:

sem_num將要執行操作的信號量組中包含的信號量數量。 sem_op是一個指定了操作類型的整數。 如果sem_op是一個正整數,則這個值會立刻被加到信號量的值上。 [BR]如果 sem_op 為負,則將從信號量值中減去它的絕對值。如果這將使信號量的值小於零,則這個操作會導致進程阻塞,直到信號量的值至少等於操作值的絕對值(由其它進程增加它的值)。 [BR]如果 sem_op 為0,這個操作會導致進程阻塞,直到信號量的值為零才恢復。 sem_flg 是一個符號位。指定 IPC_NOWAIT 以防止操作阻塞;如果該操作本應阻塞,則semop調用會失敗。如果為sem_flg指定SEM_UNDO,Linux會在進程退出的時候自動撤銷該次操作。 代碼 5.4 展示了二元信號量的等待和投遞操作。

代碼 5.4 (sem_pv.c)二元信號量等待和投遞操作

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

/* 等待一個二元信號量。阻塞直到信號量的值為正,然後將其減1 */

int binary_semaphore_wait (int semid)

{

struct sembuf operations[1];

/* 使用(且僅使用)第一個信號量 */

operations[0].sem_num = 0;

/* 減一。 */

operations[0].sem_op = -1;

/* 允許撤銷操作 */

operations[0].sem_flg = SEM_UNDO;

return semop (semid, operations, 1);

}

/* 對一個二元信號量執行投遞操作:將其值加一。 這個操作會立即返回。*/

int binary_semaphore_post (int semid)

{

struct sembuf operations[1];

/* 使用(且僅使用)第一個信號量 */

operations[0].sem_num = 0;

/* 加一 */

operations[0].sem_op = 1;

/* 允許撤銷操作 */

operations[0].sem_flg = SEM_UNDO;

return semop (semid, operations, 1);

}

指定 SEM_UNDO 標誌解決當出現一個進程仍然持有信號量資源時被終止這種特殊情況時可能出現的資源泄漏問題。當一個進程被有意識或者無意識地結束的時候,信號量的值會被調整到“撤銷”了所有該進程執行過的操作後的狀態。例如,如果一個進程在被殺死之前減小了一個信號量的值,則該信號量的值會增長。

調試信號

命令 ipcs -s 可以顯示系統中現有的信號量組的相關信息。而 ipcrm sem 命令可以從命令行刪除一個信號量組。例如,要刪除標識符為5790517的信號量組則應運行以下命令:

% ipcrm sem 5790517

相關詞條

熱門詞條

聯絡我們