在學習信號量之前先來看幾個概念:
臨界資源:同一時刻只允許一個進程訪問的資源。
臨界區:訪問臨界資源的代碼段。
原子操作:不可被打斷的操作,沒有中間狀態。
進程同步:進程間協同工作。
進程異步:進程間獨立運行,互不干擾,需要內核機制來通知。
在多進程編程中,會存在多個進程同時訪問同一個臨界資源的情況。比如變量i的初始值爲0,進程A和進程B同時執行i++。在執行i++之前,兩個進程獲得的i值都是0,再執行i++之後,i的值變爲1,i++只被執行了一次。而我們想要的結果是進程A和進程B依次執行i++。這就需要信號量來維護進程間的同步。
信號量是一個特殊的變量。它是一個計數器,大於0時記錄當前臨界資源的數量,小於等於0時記錄等待資源的進程的數量。當信號量的值大於0時,進程總是可以獲取到資源並使用;小於等於0時,表示沒有臨界資源可用,進程必須阻塞等待其他進程釋放資源。
操作方式:對信號量進行操作使用p、v操作。
p操作:獲取資源,信號量的值減1。當信號量的值小於等於0時,此操作會阻塞。
v操作:釋放資源,信號量的值加1。此操作一般情況下不會阻塞。
p、v操作都是原子操作,i++不是原子操作。一條單獨指令的執行纔是原子操作。
p操作的初始值爲多少就代表幾個資源可以被訪問。
p、v操作力度要小,儘可能只對需要訪問的臨界資源執行,提高效率。
API接口:
#include <sys/sem.h>
int semget((key_t)key,int nsems,int flag);//創建或獲取信號量的內核對象
int semctl(int semid,int semnum,int cmd,/*union semun arg*/);//設置信號量屬性
int semop(int semid,struct sembuf buff[],int size);//完成對信號量的p操作或v操作
struct sembuf
{
short sem_num;//信號量編號
short sem_op;//信號量在一次操作中需要改變的數值,p操作爲-1,v操作爲+1
short sem_flg;//通常設置爲SEM_UNDO
};
操作系統對進程間通訊用的信號量在內核中都是以信號量集管理的,即通過semget()函數獲取到的是信號量集的標識符。其他函數操作時,必須指明操作的是哪個信號量集中的那個信號量,類似於數組的下標。一個進程創建的信號量,其他進程也可訪問。
命令:
ipcs -s 查看信號量
ipcrm -s semid 刪除信號量