亞寵展、全球寵物產業風向標——亞洲寵物展覽會深度解析
817
2022-05-29
前面陸續介紹了標準管道流、無名管道、命名管道、mmap內存映射,這篇文章介紹共享內存段。
1. 共享內存機制(shmget)
共享內存也是進程間(進程間不需要有繼承關系)通信的一種常用手段。一般OS通過內存映射與頁交換技術,使進程的內存空間映射到不同的物理內存,這樣能保證每個進程運行的獨立性,不至于受其它進程的影響。但可以通過共享內存的方式,使不同進程的虛擬內存映射到同一塊物理內存,一個進程往這塊物理內存中更新的數據,另外的進程可以立即看到這塊物理內存中修改的內容。
內存映射和共享內存的區別:
mmap內存映射:跟普通文件的讀寫相比,加快對文件/設備的訪問速度。
shmget共享內存:多進程間進行通信。
原理及實現:
system V IPC機制下的共享內存本質是一段特殊的內存區域,進程間需要共享的數據被放在該共享內存區域中,所有需要訪問該共享區域的進程都要把該共享區域映射到本進程的地址空間中去。這樣一個使用共享內存的進程可以將信息寫入該空間,而另一個使用共享內存的進程又可以通過簡單的內存讀操作獲取剛才寫入的信息,使得兩個不同進程之間進行了一次信息交換,從而實現進程間的通信。共享內存允許一個或多個進程通過同時出現在它們的虛擬地址空間的內存進行通信,而這塊虛擬內存的頁面被每個共享進程的頁表條目所引用,同時并不需要在所有進程的虛擬內存都有相同的地址。進程對象對于共享內存的訪問通過key(鍵)來控制,同時通過key進行訪問權限的檢查。
2. 共享內存機制相關函數接口介紹
2.1 ftok函數
#include
函數功能: 用于創建一個關鍵字,可以用該關鍵字關聯一個共享內存段。
參數介紹:
(1) pathname:全路徑文件名,并且該文件必須可訪問。
(2) proj_id:通常傳入一非0字符。通過pathname和proj_id組合可以創建唯一的key(對任何進程都是唯一且相同的)。
返回值:
如果調用成功,返回一關鍵字,否則返回-1。
2.2 shmge函數
#include
shmget 函數用于創建或打開一共享內存段,該內存段由函數的第一個參數標識。函數成功則返回一個該共享內存段的唯一標識號(唯一的標識了這個共享內存段),對任何進程都是唯一且相同的。
參數介紹
(1) key是一個與共享內存段相關聯的關鍵字,如果事先已經存在一個與指定關鍵字關聯的共享內存段,則直接返回該內存段的標識。key的值既可以用ftok函數產生,也可以是IPC_RPIVATE(用于創建一個只屬于創建進程的共享內存,主要用于父子通信),表示總是創建新的共享內存段。
(2) size指定共享內存段的大小,以字節為單位。
(3) shmflg是一掩碼合成值,可以是訪問權限值與(IPC_CREAT或IPC_EXCL)的合成。IPC_CREAT表示如果不存在該內存段,則創建它。IPC_EXCL表示如果該內存段存在,則函數返回失敗結果(-1)。
返回值
如果調用成功,返回內存段標識,否則返回-1。
2.3 shmat函數
函數shmat將共享內存段映射到進程空間的某一地址。
#include
注意: 只有管理員用戶權限才可以獲取內存地址
參數
(1) shmid 是共享內存段的標識通常應該是shmget的成功返回值。
(2) shmaddr指定的是共享內存連接到當前進程中的地址位置。通常是NULL,表示讓系統來選擇共享內存出現的地址。
(3) shmflg是一組位標識,通常為0即可。如果是SHM_RDONLY的話,就是只讀模式。其它的是讀寫模式。
返回值
如果調用成功,返回映射后的進程空間的首地址,否則返回(void*)-1。
2.4 shmdt函數
shmdt用于將共享內存段與進程空間分離,與shmat函數相反。用于關閉共享內存段。
#include
參數
shmaddr通常為shmat的成功返回值。
返回值
成功返回0,失敗時返回-1。
注意:只是將共享內存分離,并沒有沒刪除它,只是使得該共享內存對當前進程不再可用。
2.5 shmctl函數
函數shmctl是共享內存的控制函數,可以用來刪除共享內存段。
#include
參數:
(1)shmid:共享內存段標識 通常應該是shmget的成功返回值
(2)cmd:對共享內存段的操作方式
可選為IPC_STAT,IPC_SET,IPC_RMID。通常為IPC_RMID,表示刪除共享內存段。
(3)buf:表示共享內存段的信息結構體數據,通常為NULL。
例如: shmctl(kshareMem,IPC_RMID,NULL)表示刪除共享內存段kHareMem
3. 案例: 基本用法示例1
3.1 創建內存段寫數據示例
下面代碼使用/work/1.dat的文件屬性獲取key,作為內存標識符;再創建共享內存段,映射內存地址,然后向內存空間寫入數據"hello world",再取消映射。這時候其他進程就可以訪問這個內存段讀取里面的數據。
#include
3.2 打開內存段讀取示例
下面代碼用來訪問,上面寫端代碼創建的共享內存段里的數據,流程一樣。shmget函數如果判斷出共享內存段已經存在,就不會再重復創建(依靠key作為標識符判斷的);接著再映射空間地址,讀取內存里的數據,打印出hello world,最后再銷毀內存空間。
#include
4. 案例: 基本用法示例2
上面例子代碼是通過獲取文件的屬性得到唯一的key,實際上也可以自己指定key,只要保證唯一性即可。
4.1 創建內存寫數據示例
#include
4.2 打開內存讀數據示例
#include
Linux 任務調度
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。