文章目錄
- 1.消息隊列
- 1.1 消息隊列的原理
- 1.2 消息隊列的系統接口
- 2. 信號量
- 2.1 信號量的系統調用接口
- 3. 淺談進程間通信
- 3.1 IPC在內核中數據結構設計
- 3.2 共享內存的缺點
- 3.3 理解信號量
- 序:在上一章中,我們引出了命名管道和共享內存的概念,了解了他們的底層原理和系統接口的使用,知道了共享內存的特性等,而本章,我將繼續深入System V的剩下兩種進程間通信的方式:消息隊列和信號量!!!
1.消息隊列
System V IPC{
System V —消息隊列
System V —共享內存
System V —信號量
}
本章將圍繞著system V IPC中的消息隊列和信號量來講述
1.1 消息隊列的原理
消息隊列的原理圖:
消息隊列的
1. 必須讓不同進程看到同一個隊列
2. 允許不同的進程,向內核中發送帶類型的數據塊
文件緩沖區----管道
內存塊----共享內存
隊列----消息隊列
這些都符合進程間通信的本質:必須讓不同進程看到同一份資源!!!
1.2 消息隊列的系統接口
要想使用消息隊列實現進程間通信,首先就要先將消息隊列創建出來。
第一個參數是通過ftok()函數生成的key,第二個參數是位圖參數,和之前的共享內存一樣,這個函數可以創建一個新的消息隊列
想要修改消息隊列的屬性,就要調用相關的系統接口。
向消息隊列中發送和得到數據:
其中,msgsnd是發送數據的系統調用接口,msgrcv是獲取數據的系統調用接口
消息隊列的管理結構體:
查看消息隊列
ipcs -q 能查看消息隊列信息(和ipcs -m查看共享內存一樣)
刪除消息隊列
ipcrm -q +[msgid] 能刪除消息隊列
2. 信號量
2.1 信號量的系統調用接口
要想使用信號量,和消息隊列,共享內存同理,也是要先去申請一個信號量。
和消息隊列,共享內存同理,想要修改信號量的屬性,就要調用相關的系統接口。
信號量的管理結構體:
3. 淺談進程間通信
3.1 IPC在內核中數據結構設計
在操作系統中,所有IPC資源,都是整合進操作系統的IPC模塊中的!
共享內存、消息隊列和信號量這三個的管理結構體內都有一個ipc_perm的結構體,系統通過一個數組對這樣的一個個結構體進行管理,從而對不同的IPC結構體進行管理!!!
通過在struct ipc_perm數組中存入對應IPC結構體中ipc_perm結構體的地址,我們就可以通過這個對這個ipc_perm進行處理為((struct semid_ds * )addr)(以信號量的IPC結構體為例),從而訪問到整個IPC結構體中的任意成員!!!(其中,ipc_perm中有一個類型標志位,所以操作系統能區分指針指向的對象的類型,也就知道了這是共享內存的IPC結構體還是消息隊列的IPC結構體,還是信號量的IPC結構體)
這種模式與c++中的多態有很大的相似度,對于ipc_perm結構體的復用,就像ipc_perm是基類,其他IPC結構體是子類,而實際上cpp就是基于Linux中的這些模式,而引入的多態的概念!!!
3.2 共享內存的缺點
當我們的A正在寫入,且已經寫入了一部分,就被B拿走了,導致雙方發送和收到的數據不完整-----數據不一致問題,共享內存會有這樣的問題,而管道則沒有,因為,管道會有同步互斥的保護機制。
1. A、B看到同一份資源,共享內存,如果不加保護,就會導致數據不一致問題
2. 加鎖—互斥訪問—任何時刻,都只允許一個執行流訪問共享資源—互斥(例如:去ATM機取錢的時候,一臺ATM機一次只能有一個人取錢或存錢)
3. 共享的,任何時刻只允許一個執行流訪問的資源—臨界資源—(管道)一般是內存空間。
4. 訪問臨界資源的代碼—臨界區
問題一:多進程,多線程,并發打印,此時顯示器上的消息是錯亂的,甚至和命令行混在一起,這是為什么?
在多進程、多線程中,顯示器是一種共享資源,此時,多進程、多線程往顯示器打印內容就會導致數據不一致問題,要想不錯亂,就要將這個共享資源變成一種臨界資源。
3.3 理解信號量
信號量的本質是一把計數器,類似但不等于一個int cnt = n;是用來描述臨界資源中資源數量的多少
例子:當我們看電影時,我們還沒去看,但是要先買票(買票的本質就是對資源的預定機制),其中票數計數器,每賣一張票,計數器就要減一。此時放映廳的資源就少一個!!!當票數計數器到0后,資源已經被申請完了。
問題一:我們最怕什么情況?
1. 多個執行流訪問同一個資源
2. n個執行流訪問n-1個資源
為了解決這種問題,我們就要引入一個計數器!!!
int cnt = 15;
int number = cnt–;申請資源
cnt <= 0;資源就被申請完了,再有執行流申請也不會給了!!!
1. 申請計數器資源成功,就表示我具有了訪問資源的權限了。
2. 申請了計數器資源,我當前訪問我要的資源了嗎?沒有!申請了計數器資源是對資源的預定機制。
3. 計數器可以有效保證進入共享資源的執行流的數量
4. 每一個執行流,想訪問共享資源的時候,不是直接訪問,而是先申請計數器資源,就像是看電影先買電影票
程序員把這樣一個計數器叫做信號量!!!
所以,當該票只有一個人能搶到,只有一個人能去看電影時。看電影期間只有一個執行流在訪問臨界資源—互斥!!!
我們把值只能為1,0兩態的計數器叫做二元信號量—本質就是一個鎖。
當計數器為1.本質問題:其實就是將臨界資源不要分成很多塊了,而是當做一個整體,整體申請,整體釋放!!!
問題二:要訪問臨界資源,先要申請信號量計數器資源,但是信號量計數器的本質不也是共享資源嗎???所以這個計數器也是不安全的
信號量:
a. 申請信號量,本質是對計數器減減------p操作
b. 釋放資源,釋放信號量,本質是對計數器進行加加操作------v操作
其中信號量的申請和釋放—pv操作–是原子的(一個事,要么不做,要做就做完!)
其中要強調的是,多個信號量和信號量是不同的概念
問題二:信號量憑什么是進程間通信的一種?他也沒傳送數據啊,不是說他的本質就是個計數器嗎?
1. 通信不僅僅是通信數據,互相協同也是
2. 要協同,本質也是通信,信號量首先要被所有的通信進程看到。
總結:
本章節帶領大家從原理和系統接口的視角了解了什么是消息隊列和信號量,而后對進程間通信的內核數據結構進行了探討,了解了其中的底層邏輯,最后再次深入了解什么是信號量,希望對大家能有幫助!!!