AT&T的貝爾實驗室,對Unix早期的進程間通訊進行了改進和擴充,造成了"system V IPC",其通訊進程主要侷限在單個計算機內。IPC對象指的是共享內存(share memory)、消息隊列(message queue)和信號燈集(semaphore)。數組
信號燈(semaphore),也叫信號量。緩存
本質;一種數據操做鎖(自己是一個計數器,是對臨界資源的保護),它自己不具備數據交換的功能,而是經過控制其餘的通訊資源(文件,外部設備)來實現進程間通訊,它自己只是一種外部資源的標識。信號量在此過程當中負責數據操做的互斥、同步等功能。ide
當請求一個使用信號量來表示的資源時,進程須要先讀取信號量的值來判斷資源是否可用。大於0,資源能夠請求,等於0,無資源可用,進程會進入睡眠狀態直至資源可用。當一個進程再也不使用一個信號量控制的共享資源時,信號量的值+1,對信號量的值進行的增減操做爲原子操做,這是因爲信號量主要的做用是維護資源的互斥或多進程的同步訪問。而信號量的建立以及初始化上,不能保證操做爲原子操做。函數
使用信號量的緣由:爲了防止出現因多個程序同時訪問一個共享資源而引起的一系列問題,它能夠經過生成並使用令牌來受權,在任意時刻只能有一個執行線程訪問代碼的臨界區域。臨界區域是指執行數據更新的代碼須要獨佔式地執行。而信號量就能夠提供這樣的一種訪問機制,讓一個臨界區同一時間只有一個線程在訪問它,也就是說信號量是用來協調進程對共享資源的訪問的。測試
缺點:建立和初始化分離。spa
信號燈是不一樣進程間或一個給定進程內部不一樣線程間同步的機制。System V的信號燈是一個或者多個信號燈的一個集合。其中的每個都是單獨的計數信號燈。System V 信號燈由內核維護。主要函數semget,semop,semctl。操作系統
一、semget函數:建立一個信號量集對象(獲得一個信號量集標識符)線程
函數原型:int semget(key_t key,int nsems,int semflg)3d
key:由ftok()函數的獲得對象
nsems:建立信號量集中信號的個數
semflg:
IPC_CREAT:若內核中不存在鍵值與key相等的信號量集,則建立,不然,返回此信號量集的標識符
IPC_EXCL:單獨使用無心義
IPC_CREAT | IPC_EXCL :建立一個新的信號量集並返回信號量集的標識符,不然,返回-1.
返回值:成功返回信號量集的標識符。失敗返回-1.
二、semctl函數:在指定的信號集或信號集內的某個信號上執行操做控制
函數原型: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;
三、semop函數:對信號量進行P,V操做(本文的重點)
P操做負責把當前進程由運行狀態轉換爲阻塞狀態,直到另一個進程喚醒它。操做爲:申請一個空閒資源(把信號量減1),若成功,則退出;若失敗,則該進程被阻塞;
V操做負責把一個被阻塞的進程喚醒,它有一個參數表,存放着等待被喚醒的進程信息。操做爲:釋放一個被佔用的資源(把信號量加1),若是發現有被阻塞的進程,則選擇一個喚醒之。
semop函數原型以下:
int semop(int semid, struct sembuf *sops, unsigned nsops);
semop操做中:sembuf結構的sem_flg成員能夠爲0、IPC_NOWAIT、SEM_UNDO 。爲SEM_UNDO時,它將使操做系統跟蹤當前進程對這個信號量的修改狀況,若是這個進程在沒有釋放該信號量的狀況下終止,操做系統將自動釋放該進程持有的。
sembuf結構的sem_flg成員爲SEM_UNDO時,它將使操做系統跟蹤當前進程對這個信號量的修改狀況,若是這個進程在沒有釋放該信號量的狀況下終止,操做系統將自動釋放該進程持有的信號量,從而使另一個進程能夠繼續工做,防止其餘進程由於得不到信號量而發生【死鎖現象】。爲此通常建議使用SEM_UNDO。
測試代碼:
sem.h
sem.c
semtest.c
運行結果: