一、什麼是共享記憶體區
共享記憶體區是最快的可用ipc形式。它允許多個不相關的程序去訪問同一部分邏輯記憶體。如果需要在兩個執行中的程序之間傳輸資料,共享記憶體將是一種效率極高的解決方案。一旦這樣的記憶體區對映到共享它的程序的位址空間,這些程序間資料的傳輸就不再涉及核心。這樣就可以減少系統呼叫時間,提高程式效率。
共享記憶體是由ipc為乙個程序建立的乙個特殊的位址範圍,它將出現在程序的位址空間中。其他程序可以把同一段共享記憶體段「連線到」它們自己的位址空間裡去。所有程序都可以訪問共享記憶體中的位址。如果乙個程序向這段共享記憶體寫了資料,所做的改動會立刻被有訪問同一段共享記憶體的其他程序看到。
要注意的是共享記憶體本身沒有提供任何同步功能。也就是說,在第乙個程序結束對共享記憶體的寫操作之前,並沒有什麼自動功能能夠預防第二個程序開始對它進行讀操作。共享記憶體的訪問同步問題必須由程式設計師負責。可選的同步方式有互斥鎖、條件變數、讀寫鎖、紀錄鎖、訊號燈。
二、mmap
在將共享記憶體前我們要先來介紹下面幾個函式。
mmap函式把乙個檔案或乙個posix共享記憶體區物件對映到呼叫程序的位址空間。使用該函式有三個目的:
1.使用普通檔案以提供記憶體對映i/o
2.使用特殊檔案以提供匿名記憶體對映。
3.使用shm_open以提供無親緣關係程序間的posix共享記憶體區。
1. 名稱::
mmap
功能:把i/o檔案對映到乙個儲存區域中
標頭檔案:
#include
函式原形:
void *mmap(void *addr,size_t len,int prot,int flag,int filedes,off_t off);
引數:addr 指向對映儲存區的起始位址
len 對映的位元組
prot 對對映儲存區的保護要求
flag flag標誌位
filedes 要被對映檔案的描述符
off 要對映位元組在檔案中的起始偏移量
返回值:
若成功則返回對映區的起始位址,若出錯則返回map_failed
addr引數用於指定對映儲存區的起始位址。通常將其設定為null,這表示由系統選擇該對映區的起始位址。
filedes指要被對映檔案的描述符。在對映該檔案到乙個位址空間之前,先要開啟該檔案。len是對映的位元組數。
off是要對映位元組在檔案中的起始偏移量。通常將其設定為0。
prot引數說明對對映儲存區的保護要求。可將prot引數指定為prot_none,或者是prot_read(對映區可讀),prot_write(對映區可寫),prot_exec(對映區可執行)任意組合的按位或,也可以是prot_none(對映區不可訪問)。對指定對映儲存區的保護要求不能超過檔案open模式訪問許可權。
flag引數影響對映區的多種屬性:
map_fixed 返回值必須等於addr.因為這不利於可移植性,所以不鼓勵使用此標誌。
map_shared 這一標誌說明了本程序對對映區所進行的儲存操作的配置。此標誌指定儲存操作修改對映檔案。
map_private 本標誌導致對對映區建立乙個該對映檔案的乙個私有副本。所有後來對該對映區的引用都是引用該副本,而不是原始檔案。
要注意的是必須指定map_fixed或map_private標誌其中的乙個,指定前者是對儲存對映檔案本身的乙個操作,而後者是對其副本進行操作。
mmap成功返回後,fd引數可以關閉。該操作對於由mmap建立的對映關係沒有影響。為從某個程序的位址空間刪除乙個對映關係,我們呼叫munmap.2.
名稱::
munmap
功能:解除儲存對映
標頭檔案:
#include
函式原形:
int munmap(caddr_t addr,size_t len);
引數:addr 指向對映儲存區的起始位址
len 對映的位元組
返回值:
若成功則返回0,若出錯則返回-1
其中addr引數是由mmap返回的位址,len是對映區的大小。再次訪問這些位址導致向呼叫程序產生乙個sigsegv訊號。
如果被對映區是使用map_private標誌對映的,那麼呼叫程序對它所作的變動都被丟棄掉。
核心的虛存演算法保持記憶體對映檔案(一般在硬碟上)與記憶體對映區(在記憶體中)的同步(前提它是map_shared記憶體區)。這就是說,如果我們修改了記憶體對映到某個檔案的記憶體區中某個位置的內容,那麼核心將在稍後某個時刻相應地更新檔案。然而有時候我們希望確信硬碟上的檔案內容與記憶體對映區中的檔案內容一致,於是呼叫msync來執行這種同步。
3. 名稱::
msync
功能:同步檔案到儲存器
標頭檔案:
#include
函式原形:
int msync(void *addr,size_t len,int flags);
引數:addr 指向對映儲存區的起始位址
len 對映的位元組
prot flags
返回值:
若成功則返回0,若出錯則返回-1
其中addr和len引數通常指代記憶體中的整個記憶體對映區,不過也可以指定該記憶體區的乙個子集。flags引數為ms_async(執行非同步寫),ms_sync(執行同步寫),ms_invalidate(使快取記憶體的資料實效)。其中ms_async和ms_sync這兩個常值中必須指定乙個,但不能都指定。它們的差別是,一旦寫操作已由核心排入佇列,ms_async即返回,而ms_sync則要等到寫操作完成後才返回。如果還指定了ms_invalidate,那麼與其最終拷貝不一致的檔案資料的所有記憶體中拷貝都失效。後續的引用將從檔案取得資料。
4. 名稱::
memcpy
功能:複製對映儲存區
標頭檔案:
#include
函式原形:
void *memcpy(void *dest,const void *src,size_t n);
引數:dest 待複製的對映儲存區
src 複製後的對映儲存區
n 待複製的對映儲存區的大小
返回值:
返回dest的首位址
memcpy拷貝n個位元組從dest到src。
下面就是利用mmap函式影射i/o實現的cp命令。
/*mycp.c*/
#include
#include
#include
#include
#include
int main(int argc,char *argv)
if((fdin=open(argv[1],o_rdonly))<0) /*開啟原檔案*/
perror(argv[1]);
if((fdout=open(argv[2],o_rdwr|o_creat|o_trunc))<0)/*建立並開啟目標檔案*/
perror(argv[2]);
if(fstat(fdin,&statbuf)<0) /*獲得檔案大小資訊*/
printf(「fstat error」);
if(lseek(fdout,statbuf.st_size-1,seek_set)==-1)/*初始化輸出對映儲存區*/
printf(「lseek error」);
if(write(fdout,」1」)!=1)
printf(「write error」);
if((src=mmap(0,statbuf.st_size,prot_read,map_shared,fdin,0))==map_failed)
/*對映原檔案到輸入的對映儲存區*/
printf(「mmap error);
if((dst=mmap(0,statbuf.st_size,prot_read|prot_write,map_shared,fdout,0)) ==map_failed) /*對映目標檔案到輸出的對映儲存區*/
printf(「mmap error);
memcpy(dst,src,statbuf.st_size);/*複製對映儲存區*/
munmap(src,statbuf.st_size); /*解除輸入對映*/
munmap(dst,statbuf.st_size); /*解除輸出對映*/
close(fdin);
close(fdout);
}下面是執行結果:
#cc –o mycp mycp.c
#./mycp test1 test2
共享記憶體區
共享記憶體區是最快的ipc形式。一旦這樣的記憶體對映到共享它的程序的位址空間,這些程序間資料傳遞不再涉及到核心,換句話說是程序不再通過執行進入核心的系統呼叫來傳遞彼此的資料。mmap 函式 功能 將檔案或者裝置空間對映到共享記憶體區。原型void mmap void addr,size t len,...
Posix共享記憶體區
1 概述 posix提供了兩種在無親緣關係程序間共享記憶體區的方法 者兩種方法多需要呼叫mmap,差別在於作為mmap的引數之一的描述符的獲取手段。2 posix共享記憶體區物件 posix共享記憶體區涉及以下兩個步驟要求 1 指定乙個名字引數呼叫shm open,以建立乙個新的共享記憶體區物件或開...
System V 共享記憶體區
system v共享記憶體區在概念上類似於posix共享記憶體區。代之以呼叫shm open後呼叫mmap的是,先呼叫shmget,再呼叫shmat函式。shmget函式建立乙個尚未存在的共享記憶體區,或者訪問乙個已經存在的共享記憶體區。include int shmget key t key,si...