概念:這種機制容許兩個或多個進程經過把公共數據結構放入一個共享內存區來訪問它們。若是進程要訪問這種數據結構所在的共享內存區,就必須在本身的地址空間中增長一個新線性區,新線性區映射與這個共享內存區相關的頁框。這樣的頁框能夠由內核經過請求調頁進行簡單的處理。數據結構
優勢:共享內存(shared memory)是最簡單的最大自由度的Linux進程間通訊方式之一。使用共享內存,不一樣進程能夠對同一塊內存進行讀寫。因爲全部進程對共享內存的訪問就和訪問本身的內存空間同樣,而不須要進行額外系統調用或內核操做,同時還避免了多餘的內存拷貝,因此,這種方式是效率最高、速度最快的進程間通訊方式。dom
缺點:內核並不提供任何對共享內存訪問的同步機制,好比同時對共享內存的相同地址進行寫操做,則後寫的數據會覆蓋以前的數據。因此,使用共享內存通常還須要使用其餘IPC機制(如信號量)進行讀寫同步與互斥。
函數
基本原理指針
瞭解Linux內存管理機制,就很容易知道共享內存的原理了。你們知道,內核對內存的管理是以頁(page)爲單位的,Linux下通常一個page大小是4k。而程序自己的虛擬地址空間是線性的,因此內核管理了進程從虛擬地址空間到起對應的頁的映射。建立共享內存空間後,內核將不一樣進程虛擬地址的映射到同一個頁面:因此在不一樣進程中,對共享內存所在的內存地址的訪問最終都被映射到同一頁面。下圖演示了共享內存的工做機制:進程
使用方法內存
共享內存的使用過程可分爲 建立->鏈接->使用->分離->銷燬 這幾步。資源
共享內存的建立使用shmget函數(SHared Memory GET)函數,使用方法以下:get
int segment_id = shmget (shm_key, getpagesize (),IPC_CREAT | S_IRUSR | S_IWUSER);
shmget根據shm_key建立一個大小爲page_size的共享內存空間,參數3是一系列的建立參數。若是shm_key已經建立,使用該shm_key會返回能夠鏈接到該以建立共享內存的id。
建立後,爲了使共享內存能夠被當前進程使用,必須緊接着進行鏈接操做。使用函數shmat(SHared Memory ATtach),參數傳入經過shmget返回的共享內存id便可:同步
shared_memory = (char*) shmat (segment_id, 0, 0);
shmat返回映射到進程虛擬地址空間的地址指針,這樣進程就能像訪問一塊普通的內存緩衝同樣訪問共享內存。例子中後兩個參數咱們所有傳入0,採用默認的鏈接方式。實際上,第二個參數是但願鏈接的進程虛擬地址空間的地址,若是使用0,Linux會本身選用一個合適的地址;第三個參數是鏈接選項,能夠是:
SHM_RND:將第二個參數指向的內存空間自動提高到page size的整數倍,若是不知明該參數,你須要本身控制第二個參數所指內存空間的大小。it
SHM_RDONLY:該共享內存是隻讀的,不可寫。
當共享內存使用完畢後,使用函數shmdt (SHared Memory DeTach)進行解鏈接。該函數以shmat返回的內存地址做爲參數。每最後一個使用該共享內存的進程分離該共享內存後,內核將會對該共享內存自動銷燬。固然,咱們最好能顯式的進行銷燬,以免沒必要要的共享內存資源浪費。 函數shmctl (SHared Memory ConTroL)能夠返回共享內存的信息並對其進行控制,如
shmctl (segment_id, IPC_STAT, &shmbuffer);
能夠返回該共享內存的信息,並將信息保存在第三個參數指向的shmid_ds結構體中。
當向第二個參數傳入IPC_RMID時,共享內存將會在最後一個使用該共享內存的進程分離共享內存是銷燬共享內存。
shmctl還有不少其餘使用方法, 再也不贅述。
示例程序
下面的示例程序,a進程每一秒的向共享內存寫入一個隨機數,b進程每隔一秒從該共享內存讀出該數。
/*
* a.c
* write a random number between 0 and 999 to the shm every 1 second
*/
#include<stdio.h>
#include<unistd.h>
#include<sys/shm.h>
#include<stdlib.h>
#include<error.h>
int main(){
int shm_id;
int *share;
int num;
srand(time(NULL));
shm_id = shmget (1234, getpagesize(), IPC_CREAT);
if(shm_id == -1){
perror("shmget()");
}
share = (int *)shmat(shm_id, 0, 0);
while(1){
num = random() % 1000;
*share = num;
printf("write a random number %d\n", num);
sleep(1);
}
return 0;
}
/* * b.c * read from the shm every 1 second*/#include<stdio.h>#include<unistd.h>#include<sys/shm.h>#include<stdlib.h>#include<error.h>int main(){ int shm_id; int *share; shm_id = shmget (1234, getpagesize(), IPC_CREAT); if(shm_id == -1){ perror("shmget()"); } share = (int *)shmat(shm_id, 0, 0); while(1){ sleep(1); printf("%d\n", *share); } return 0;}