共享內存能夠說是最有用的進程間通訊方式,也是最快的IPC形式。是針對其餘通訊機制運行效率較低而設計的。兩個不一樣進程A、B共享內存的意思是,同一塊物理內存被映射到進程A、B各自的進程地址空間。進程A能夠即時看到進程B對共享內存中數據的更新,反之亦然。因爲多個進程共享同一塊內存區域,必然須要某種同步機制,互斥鎖和信號量均可以。node
採用共享內存通訊的一個顯而易見的好處是效率高,由於進程能夠直接讀寫內存,而不須要任何數據的拷貝。對於像管道和消息隊列等通訊方式,則須要在內核和用戶空間進行四次的數據拷貝,而共享內存則只拷貝兩次數據[1]:一次從輸入文件到共享內存區,另外一次從共享內存區到輸出文件。實際上,進程之間在共享內存時,並不老是讀寫少許數據後就解除映射,有新的通訊時,再從新創建共享內存區域。而是保持共享區域,直到通訊完畢爲止,這樣,數據內容一直保存在共享內存中,並無寫回文件。共享內存中的內容每每是在解除映射時才寫回文件的。所以,採用共享內存的通訊方式效率是很是高的。數組
進程間須要共享的數據被放在一個叫作IPC共享內存區域的地方,全部須要訪問該共享區域的進程都要把該共享區域映射到本進程的地址空間中去。系統V共享內存經過shmget得到或建立一個IPC共享內存區域,並返回相應的標識符。內核在保證shmget得到或建立一個共享內存區,初始化該共享內存區相應的shmid_kernel結構體的同時,還將在特殊文件系統shm中,建立並打開一個同名文件,並在內存中創建起該文件的相應dentry及inode結構,新打開的文件不屬於任何一個進程(任何進程均可以訪問該共享內存區)。全部這一切都是系統調用shmget完成的。數據結構
注:每個共享內存區都有一個控制結構struct shmid_kernel,shmid_kernel是共享內存區域中很是重要的一個數據結構,它是存儲管理和文件系統結合起來的橋樑,定義以下:ide
struct shmid_kernel /* private to the kernel */ { struct kern_ipc_perm shm_perm; /* operation permission structure */ struct file *shm_file; /* pointer in kernel */ unsigned long shm_nattch; /* number of current attaches */ unsigned long shm_segsz; /* size of segment in bytes */ time_t shm_atim; /* last-attach time */ time_t shm_dtim; /* last-detach time */ time_t shm_ctim; /* last-change time */ pid_t shm_cprid; /* pid of creator */ pid_t shm_lprid; /* pid of last shmop() */ };
正如消息隊列和信號燈同樣,內核經過數據結構struct ipc_ids shm_ids維護系統中的全部共享內存區域。上圖中的shm_ids.entries變量指向一個ipc_id結構數組,而每一個ipc_id結構數組中有個指向kern_ipc_perm結構的指針。到這裏讀者應該很熟悉了,對於系統V共享內存區來講,kern_ipc_perm的宿主是 shmid_kernel結構,shmid_kernel是用來描述一個共享內存區域的,這樣內核就可以控制系統中全部的共享區域。同時,在 shmid_kernel結構的file類型指針shm_file指向文件系統shm中相應的文件,這樣,共享內存區域就與shm文件系統中的文件對應起來。spa
在建立了一個共享內存區域後,還要將它映射到進程地址空間,系統調用shmat()完成此項功能。因爲在調用shmget()時,已經建立了文件系統 shm中的一個同名文件與共享內存區域相對應,所以,調用shmat()的過程至關於映射文件系統shm中的同名文件過程,原理與mmap()大同小異。設計
頭文件:
#include <sys/ipc.h>
#include <sys/shm.h>
shmget()用來得到共享內存區域的ID,若是不存在指定的共享區域就建立相應的區域。shmat()把共享內存區域映射到調用進程的地址空間中去,這樣,進程就能夠方便地對共享區域進行訪問操做。shmdt()調用用來解除進程對共享內存區域的映射。shmctl實現對共享內存區域的控制操做。指針
在/proc/sys/kernel/目錄下,記錄着系統V共享內存的一下限制,如一個共享內存區的最大字節數shmmax,系統範圍內最大共享內存區標識符數shmmni等,能夠手工對其調整,但不推薦這樣作。code
/***** testwrite.c *******/ #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <unistd.h> typedef struct{ char name[4]; int age; } people; main(int argc, char** argv) { int shm_id,i; key_t key; char temp; people *p_map; char* name = "/dev/shm/myshm2"; key = ftok(name,0); if(key==-1) perror("ftok error"); shm_id=shmget(key,4096,IPC_CREAT); if(shm_id==-1) { perror("shmget error"); return; } p_map=(people*)shmat(shm_id,NULL,0); temp='a'; for(i = 0;i<10;i++) { temp+=1; memcpy((*(p_map+i)).name,&temp,1); (*(p_map+i)).age=20+i; } if(shmdt(p_map)==-1) perror(" detach error "); } /********** testread.c ************/ #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <unistd.h> typedef struct{ char name[4]; int age; } people; main(int argc, char** argv) { int shm_id,i; key_t key; people *p_map; char* name = "/dev/shm/myshm2"; key = ftok(name,0); if(key == -1) perror("ftok error"); shm_id = shmget(key,4096,IPC_CREAT); if(shm_id == -1) { perror("shmget error"); return; } p_map = (people*)shmat(shm_id,NULL,0); for(i = 0;i<10;i++) { printf( "name:%s\n",(*(p_map+i)).name ); printf( "age %d\n",(*(p_map+i)).age ); } if(shmdt(p_map) == -1) perror(" detach error "); }