文章目錄
- 原理
- shmget
- ftok
- shmat(share memory attach)
- shmdt,去關聯(share memory delete attach)
- shmctl ,刪除共享內存
- 共享內存與管道
原理
共享內存本質讓不同進程看到同一份資源。
申請共享內存:
1、操作系統在物理內存當中申請一塊內存空間
2、將申請好的內存分別掛接到各自進程的進程地址空間上
具體如何掛接:
將這塊內存空間經過各自進程的頁表映射到進程地址空間的共享區中,給應用層返回共享內存的起始虛擬地址
從而實現了進程A和進程B通過各自的頁表訪問同一塊物理內存
當前進程如何釋放共享內存:
1、把當前進程與共享內存去掉關聯,把頁表的映射關系去掉
2、釋放共享內存
申請共享內存、掛接、去掉關聯、釋放共享內存這些操作都不是進程直接操作的,是由操作系統來完成
在系統當中可能會有大量的進程在進行通信,因此系統當中就可能存在大量的共享內存,那么操作系統必然要對其進行管理,所以共享內存除了在內存當中真正開辟空間之外,系統一定還要為共享內存維護相關的內核數據結構
共享內存的數據結構:
struct shmid_ds {struct ipc_perm shm_perm; /* operation perms */int shm_segsz; /* size of segment (bytes) */__kernel_time_t shm_atime; /* last attach time */__kernel_time_t shm_dtime; /* last detach time */__kernel_time_t shm_ctime; /* last change time */__kernel_ipc_pid_t shm_cpid; /* pid of creator */__kernel_ipc_pid_t shm_lpid; /* pid of last operator */unsigned short shm_nattch; /* no. of current attaches */unsigned short shm_unused; /* compatibility */void *shm_unused2; /* ditto - used by DIPC */void *shm_unused3; /* unused */
};
struct ipc_perm{__kernel_key_t key;__kernel_uid_t uid;__kernel_gid_t gid;__kernel_uid_t cuid;__kernel_gid_t cgid;__kernel_mode_t mode;unsigned short seq;
};
shmget
key:
1、必須在內核中具有唯一性,能夠讓不同的進程進行唯一性標識
2、第一個進程可以通過key創建共享內存,第二個之后的進程,只要拿著同一個key就可以和第一個進程看到同一個共享內存了
3、對于一個已經創建好的共享內存,key在哪 ?
key在共享內存的描述對象中
傳入shmget函數的第一個參數key,需要我們使用ftok函數進行獲取
size:
表示待創建共享內存的大小。
shmflg:
表示創建共享內存的方式
1、IPC_CREAT(單獨使用):
如果內核中不存在鍵值與key相等的共享內存,則新建一個共享內存并返回該共享內存的句柄;如果存在這樣的共享內存,則直接返回該共享內存的句柄
句柄:我們把具有標定某種資源能力的東西叫做句柄,而這里shmget函數的返回值實際上就是共享內存的句柄,這個句柄可以在用戶層標識共享內存,當共享內存被創建后,我們在后續使用共享內存的相關接口時,都是需要通過這個句柄對指定共享內存進行各種操作
2、IPC_CREAT | IPC_EXCL:
如果內核中不存在鍵值與key相等的共享內存,則新建一個共享內存并返回該共享內存的句柄;如果存在這樣的共享內存,則出錯返回
IPC_EXCL:不單獨使用!
ftok
ftok函數的作用就是,將一個已存在的路徑名pathname和一個整數標識符proj_id轉換成一個key值,稱為IPC鍵值,在使用shmget函數獲取共享內存時,這個key值會被填充進維護共享內存的數據結構當中。需要注意的是,pathname所指定的文件必須存在且可存取
使用ftok函數生成key值可能會產生沖突,此時可以對傳入ftok函數的參數進行修改。
需要進行通信的各個進程,在使用ftok函數獲取key值時,都需要采用同樣的路徑名和和整數標識符,進而生成同一種key值,然后才能找到同一個共享資源
顯示系統中正在使用的System V共享內存段的信息
[cxq@iZ7xviiy0goapxtblgih6oZ 1. sharemem]$ ipcs -m
共享內存的生命周期是隨內核的,內核存在,共享內存就存在
用戶不主動關閉,共享內存會一直存在
如果想要關閉共享內存,只能內核重啟(用戶釋放)
關閉共享內存:
0是shmid
[cxq@iZ7xviiy0goapxtblgih6oZ 1. sharemem]$ ipcrm -m 0
shmat(share memory attach)
讓當前進程和指定的共享內存關聯起來
shmdt,去關聯(share memory delete attach)
shmctl ,刪除共享內存
第一個參數shmid,表示所控制共享內存的用戶級標識符。
第二個參數cmd,表示具體的控制動作。
shmctl函數的第二個參數傳入的常用的選項有以下三個
1、IPC_STAT,獲取共享內存的當前關聯值,此時參數buf作為輸出型參數
2、IPC_SET ,在進程有足夠權限的前提下,將共享內存的當前關聯值設置為buf所指的數據結構中的值
3、IPC_RMID ,刪除共享內存段
第三個參數buf,用于獲取或設置所控制共享內存的數據結構
代碼:兩個進程之間通信,使用共享內存和管道
共享內存與管道
管道通信:
將一個文件從一個進程傳輸到另一個進程需要進行四次拷貝操作
1、server將信息從輸入文件復制到server的臨時緩沖區中。
2、將server臨時緩沖區的信息復制到管道中。
3、client將信息從管道復制到client的緩沖區中。
4、將client臨時緩沖區的信息復制到輸出文件中。
使用共享內存進行通信,將一個文件從client傳輸到server只需要進行兩次拷貝操作
1、從輸入文件到共享內存。
2、從共享內存到輸出文件。
優:共享內存是所有進程間通信方式中最快的一種通信方式,因為該通信方式需要進行的拷貝次數最少
缺:管道是自帶同步與互斥機制的,但是共享內存并沒有提供任何的保護機制,包括同步與互斥。