信號量的使用和原理
信號量和信號是不同的IPC通信機制,信號量是在進程之間傳遞是一個整數值,信號量只有三種操作可以進行:初始化,P操作,V操作,我們看一下具體的使用函數和數據結構。
#include<sys/sem.h>
?
int semget(key_t key, int num_sems, int sem_flags);//創建新信號量或獲取已有的信號量
int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);//改變信號量的值
?
struct sembuf{
short sem_num;
short sem_op;//通常是兩個數,一個是-1,即P操作,一個是+1,即V操作。
short sem_flg;//跟蹤信號
};
我們通過semget()函數獲取或者創建一個信號量,并返回一個信號量id,有了這個id,我們就可以通過semop()函數進行V和P的操作。
由于信號量只能進行兩種操作即"等待"和"發送",即P(sv)和V(sv),他們的行為是這樣:
- P(sv):如果sv的值大于零,就給它減1;如果它的值為零,就掛起該進程的執行
- V(sv):如果有其他進程因等待sv而被掛起,就讓它恢復運行,如果沒有進程因等待sv而掛起,就給它加1。
- 舉個例子,就是兩個進程共享信號量sv,一旦其中一個進程執行了P(sv)操作,他將得到信號量,并可以進如臨界區,使sv減1。而第二個進程將被阻止進入臨界區,因為當它試圖執行P(sv)時,sv為0,它會掛起以等待第一個進程離開臨界區并執行(sv)釋放信號。
這三種操作都是原子操作,我們通常用信號量來進行并發和同步的控制。
信號量的分類
Linux提供兩種信號量
- 內核信號量:由內核控制路徑使用
- 用戶態進程使用的信號量:這種信號量又分為POSIX信號量和SYSTEM V信號量
- POSIX辛信號量又分為有名信號量和無名信號量
- 有名信號量:其值保存在文件中,所以它可以用于線程也可以用于進程間同步
- 無名信號量:其值保存在內存。
POSIX信號量和SYSTEM V信號量的比較
對POSIX來說,信號量是個非負數。常用于線程間同步
而SYSTEM V信號量則是一個或者多個信號量集合,他對應的是一個信號量的結構體,這個結構體為SYSTEM V IPC服務的,信號量只不過是它的一部分。常用語進程間同步。POSIX信號量的引用頭文件是<semaphore,h>,而SYSTEM V信號量的引用頭文件是<sys/sem.h>
從使用的角度,System V信號量是簡單的。比如,POSIX信號量的創建和初始化PV操作就很方便。
不免要提一下互斥鎖Mutex,信號量可以是非負整數,互斥鎖只能是0和1兩個值,我們可以將Mutex理解為特殊的信號量。
在大部分情況下,用互斥鎖來做并發的控制會比信號量更方便。
什么是信號量
- 信號量又稱為信號燈,它用來協調不用進程間的數據對象,而最主要的應用是共享內存方式的進程間通信。
- 本質上,信號量時一個計數器,他用來記錄某個資源(如共享內存)的存取狀況。信號量的使用,主要是用來保護共享資源,使得資源在一個時刻只有一個進程(線程)所擁有。
- 信號量的值為正的時候,說明它空閑。所有的線程可以鎖定而使用它。若為0,說明它被占用,測試的線程要進入睡眠隊列中,等待被喚醒。
信號量的注意事項
- 為了防止出現因多個程序同時訪問一個共享資源而引發的一系列問題,我們需要這一種方法,它可以通過生成并使用令牌來授權,在任一時刻只能由一個執行線程訪問代碼的臨界區域
- 臨界區域是指執行數據更新的代碼需要獨占式地執行。而信號量就可以提供這樣的一種訪問機制,讓一個臨界區同一時間只有一個線程在訪問它,也就說信號量臨界區是指執行數據更新的代碼需要獨占式地執行。而信號量就可以提供這樣的一種訪問機制,讓一個臨界區同一時間只有一個線程在訪問它,也就說信號量是用來協調進程對共享資源的訪問。
- 信號量時一個特殊的變量,程序對其訪問都是原子操作,且只允許對它進行等待(即P-信號變量)和發送(即V信號變量)信息操作。
- 最簡單的信號量只能取0和1的變量,這也是信號量最常見的一種形式,叫做二進制信號量。而可以取多個正整數的信號量被稱為通用信號量