信號量的本質是一種數據操作鎖,它本身不具有數據交換的功能,而是通過控制其他的通信資源(文件,外部設備)來實現進程間通信,它本身只是一種外部資源的標識。信號量就是一個計數器。
當請求一個使用信號量來表示的資源時,進程需要先讀取信號量的值來判斷資源是否可用。大於0,資源可以請求,等於0,無資源可用,進程會進入睡眠狀態直至資源可用。當一個進程不再使用一個信號量控制的共享資源時,信號量的值+1,對信號量的值進行的增減操作爲原子操作,這是由於信號量主要的作用是維護資源的互斥或多進程的同步訪問。而信號量的創建以及初始化上,不能保證操作爲原子操作。
使用信號量的原因:爲了防止出現因多個程序同時訪問一個共享資源而引發的一系列問題,它可以通過生成並使用令牌來授權,在任意時刻只能有一個執行線程訪問代碼的臨界區域。臨界區域是指執行數據更新的代碼需要獨佔式地執行。而信號量就可以提供這樣的一種訪問機制,讓一個臨界區同一時間只有一個線程在訪問它,也就是說信號量是用來協調進程對共享資源的訪問的。
信號量的工作原理:
由於信號量只能進行兩種操作等待和發送信號,即P(sv)和V(sv)
P(sv):如果sv的值大於0,就減1,如果它的值爲0,就掛起該進程的執行
V(sv):如果有其他進程因等待sv而被掛起,就讓它恢復運行,如果沒有進程因等待sv而掛起,就+1
幾個函數:
創建一個信號量集對象(得到一個信號量集標識符)
int semget(key_t key,int nsems,int semflg)
key:由ftok()函數的得到
nsems:創建信號量集中信號的個數
semflg:
IPC_CREAT:若內核中不存在鍵值與key相等的信號量集,則創建,否則,返回此信號量集的標識符
IPC_EXCL:單獨使用無意義
IPC_CREAT | IPC_EXCL :創建一個新的信號量集並返回信號量集的標識符,否則,返回-1.
返回值:成功返回信號量集的標識符。失敗返回-1.
2. 完成對信號量的P,V操作
int semop(int semid,struct sembuf* sops,unsigned nsops)
返回值:成功時,返回信號量集的標識符。否則,返回-1.
semid:信號量集標識符
nsops:進行操作信號量的個數,即sops結構變量的個數,需大於或等於1.
sops:指向進行操作的信號量集結構體數組的首地址
struct sembuf
{
short semnum;//信號量集合中的信號量編號,0代表第一個信號量
short val;//val>0 進行V操作信號量值+val,表示進程釋放控制的資源
short flag; //設置信號量的默認操作 IPC_NOWAIT 設置信號量操作不等待
//SEM_UNDO 選項會讓內核記錄一個與調用進程相關的UNDO記錄,如果該進 程崩潰,則根據這個進程的UNDO記錄自動恢復相應的信號量的計數
}
當操作信號量(semop)時,flg可以設置SEM_UNDO標識;SEM_UNDO用於將修改的信號量值在進程正常退出(調用exit退出或main執行完)或異常退出(如段異常、除0異常、收到KILL信號等)時歸還給信號量。
如信號量初始值是20,進程以SEM_UNDO方式操作信號量減2,減5,加1;在進程未退出時,信號量變成20-2-5+1=14;在進程退出時,將修改的值歸還給信號量,信號量變成14+2+5-1=20。
3.在指定的信號集或信號集內的某個信號上執行操作控制
函數原型:int semctl(int semid,int semnum,int cmd,union semun arg)
semid: 信號量集標識符
semnum:信號量集數組上的下標,表示某一個信號量
arg:
union semun {
short val; /*SETVAL用的值*/
struct semid_ds* buf; /*IPC_STAT、IPC_SET用的semid_ds結構*/
unsigned short* array; /*SETALL、GETALL用的數組值*/
struct seminfo *buf; /*爲控制IPC_INFO提供的緩存*/
} arg;
“comm.h”
“comm.c”
“test.c”
測試結果: