IPC--信号量
信號量概念理解
- 信號量本質上 是一個計數器,用來統計臨界資源申請資源的個數。其中的二元信號量的 值是0或者是1,即是要么是有,要么是無。信號量本身也是臨界資源,所以一定要保證其原子性。
- 信號量的工作原理:兩個進程共享一個信號量sv,一個進程訪問的sv的時候,進行的是P操作即是減1操作,開始的時候信號量是1,它得到信號量進入臨界資源。當他出來的時候進行v操作,使信號量加1。其他的進程訪問的時候看見信號量是0,就不在訪問了。
- 現實形象比喻:比如我們的信號量是一個教室的,教室里面有很多座位,這就是臨界資源。咱們設計是50,一開始同學想進教室的時候得去申請,比如現在門口站了一個人,它就是控制信號量的,第一個人進去的時候,使用P操作,將50減1,出來的時候加1,如果信號量是>0的 就可以進去,否則就不可以進去
- 信號量 不以傳送數據為目的,它是以協調使用臨界資源進行 進程間通信為目的的,當我們申請信號量的時候,就可以得到信號量保護的臨界資源。
信號量相關函數的使用
得到信號量(生成信號量)
int semget(key_t key,int nsem,int semflg)
參數解析
- key:這是一個key值,可以理解為一個端口,這個用函數ftok生成,一會介紹
- nsem:信號量的個數
- semflg:創建信號量的方式,它由兩個固定標識位參數可以選擇。如果是IPC_CREAT,表示如果有一個信號量則返回,如果沒有則創建。IPC_EXCL,如果單獨使用它沒有任何的意義,但是如果和IPC_CREAT一起使用,就是IPC_CREAT|IPC_EXCL表示如果有信號量則出錯返回,如果沒有則創建,這樣就可以保證我們每次使用的時候創建的是一個全新的信號量
返回值
如果失敗返回-1,如果成功返回信號量標識符(信號量ID)
刪除信號量
int semctl(int semid,int semnum,int cmd,...)
參數:
- semid:這個是刪除的信號量的標識符(ID)
- semnum:這個是刪除的信號量的個數,這里暫時設置0
- cmd:執行命令的方式,這里我們主要是為了刪除一個信號量,可以直接使用IPC_RMID
初始化信號量
int semctl(int semid,int semnum,int cmd,...)
- semid:這個是初始化信號量的標識符(ID)
- semnum:這個是初始化信號量中的第幾個信號量,數組下標的形式
- cmd:執行命令的方式,這里我們是初始化信號量,傳入的是特定的參數SETVAL,傳入這個信號量的時候,需要傳入第四個參數,這個參數應該是一個聯合體,聯合體的結構如下
union semnu{int val; // 使用的值struct semid_ds *buf; // IPC_STAT、IPC_SET 使用緩存區unsigned short *array; // GETALL,、SETALL 使用的數組struct seminfo *__buf; // IPC_INFO(Linux特有) 使用緩存區
};
我們在使用semctl進行 信號量初始化的時候,首先得先用上面的聯合體定義一個對象,然后這個聯合體是需要我們自己定義的,然后把實例化的這個對象的val設置為1(這里我們使用的是二元信號量)
函數使用示例:
union semnu _semnu;
semctl(semid,semnum,SETVAL,_semnu);
返回值:失敗返回-1
信號量Pv操作
int semop(int semid,struct sembuf* sops,unsigned nsops)
參數
- semid:信號量標識符
- sops:這個也是需要我們提前實例化一個對象,這里我們可以傳遞的是一個結構體數組,也可以是一個結構體的地址
- nspos:是結構體的個數,因為上一個參數是一個數組
這里第二個參數也是一個結構體,這個結構體是系統自定義的結構體,不需要我們定義,我們可以直接調用它,這里結構體的內容 如下
struct sembuf{unsigned short sem_num;short sem_op;short sem_flag;
};
num:標記信號量集中的第幾個
sem_op:標記是那種操作,比如二元信號量p設置為-1,如果是v操作設置為1
sem_flag:我們此時默認設置為0
討論信號量的幾種情況
- 當我們的某一個進程已經進行 p操作,拿到信號量維護的共享資源之后,這個時候可以有一種可能該進程被其他進程替換掉了,但是這個時候信號量依然被該進程拿著,等它下一次切換進來的時候還可以繼續原來的操作
- 另外的一種情況是,某一進程拿到信號量之后,因為某些原因被殺死,這個時候信號量還在改進程里面,其他的進程就無法獲得該信號量,這個情況就是問題所在。這個時候我們可以設置信號量的的結構體,就是上面的結構體sem_flag,可以把它設置為SEM_UNDO,這個時候進程退出的時候,它所拿到的信號量就會釋放掉,比如二元信號量原來是0,如果使用這個選項后,當進程退出后就會變成是1。
補充兩個linux的指令:
- ipcs -s :查看當前信號量
- ipcrm -s 信號量標識符:刪除某一個信號量
- ipcs -q:查看當前消息隊列數
- ipcrm -q 消息隊列標識符:刪除某一個消息隊列
總結