本文參考《嵌入式linux開發教程》和《linux/unix系統程式設計手冊》。
共享記憶體是允許兩個不相關的程序訪問同乙個邏輯記憶體的程序間通訊方法,是在兩個正在執行的程序之間共享和傳遞資料的一種非常有效的方式。
不同程序之間的共享記憶體通常安排為同一段物理記憶體。程序可以將同一段共享記憶體連線到它們自己的位址空間中,所有程序都可以訪問共享記憶體中的位址,就好像它們是由用 c語言 malloc()分配的記憶體一樣。兩個程序使用共享記憶體的通訊機制如圖所示。
posix 共享記憶體區涉及四個主要步驟:
1.指定乙個名字引數呼叫 shm_open,以建立乙個新的共享記憶體區物件(或開啟乙個已經存在的共享記憶體區物件);
2.呼叫 mmap 把這個共享記憶體區對映到呼叫程序的位址空間;
3.呼叫 munmap() 取消共享記憶體對映;
4.呼叫 shm_unlink()函式刪除共享記憶體段。
在編譯 posix 共享記憶體應用程式時需要加上-lrt 引數。
shm_open()函式用來開啟或者建立乙個共享記憶體區,兩個程序可以通過給 shm_open()函式傳遞相同的名字以達到操作同一共享記憶體的目的。
int
shm_open
(const
char
*name,
int oflag, mode_t mode)
;
函式成功返回建立或開啟的共享記憶體描述符,與檔案描述符作用相同,供後續操作使用,失敗則返回-1。
當使用完共享記憶體後,需要將其刪除,以便釋放系統資源,可通過 shm_unlink()函式完成。
int
shmunlink
(const
char
*name)
;
函式成功返回 0,否則返回-1。引數 name 為共享記憶體的名字。
建立乙個共享記憶體後,其預設大小為 0,所以需要設定該共享記憶體的大小。
int
ftruncate
(int fd, off_t length)
;
函式成功返回 0,失敗返回-1。引數 fd 為需要調整的共享記憶體或者檔案的描述符,length 為需要調整的大小。
建立共享記憶體後,需要將這塊記憶體區域對映到呼叫程序的位址空間中,可通過 mmap()函式來完成。
void
*mmap
(void
*addr, size_t length,
int prot,
int flags,
int fd, off_t offset)
;
函式成功返回對映後指向共享記憶體的虛擬位址,失敗返回 map_failed 值。
已經建立的共享記憶體對映,可通過 munmap()函式來取消。
int
munmap
(void
*addr, size_t length)
;
引數 addr 為 mmap()函式返回的位址,length 是對映的位元組數。取消對映後再對對映位址訪問會導致呼叫程序收到 sigse** 訊號。
程式清單write.c與程式清單read.c兩個範例實現了兩個無關程序間使用共享記憶體進行通訊的功能。乙個程序往共享記憶體起始位址寫入乙個整形資料12,另乙個程序則檢測該區域的資料,如果不是12,繼續等待,直到資料變化為12。
程式清單write.c所示**完成共享記憶體寫操作,先建立共享記憶體,設定大小並完成對映,隨後往共享記憶體起始位址寫入乙個值為12 的整形資料,最後取消和刪除共享記憶體。
vmuser@vmuser-virtual-machine:
~/workspace/test$ cat write.c
#include
#include
#include
#include
#include
#include
#include
#define shmsize 10
//共享記憶體大小,10 位元組
#define shmname "shmtest"
//共享記憶體名稱
intmain()
/* 設定共享記憶體大小*/
ftruncate
(fd, shmsize)
;//設定大小為 shmsize
/*對映共享記憶體*/
ptr =
mmap
(null
, shmsize, prot_read | prot_write, map_shared, fd,0)
;if(ptr == map_failed)
*ptr =
0x12
;//往起始位址寫入 12
munmap
(ptr, shmsize)
;//取消對映
shm_unlink
(shmname)
;//刪除共享記憶體
return0;
}
程式清單read.c所示範例為讀共享記憶體,首先建立共享記憶體,然後設定大小並對映共享記憶體,最後檢測共享記憶體首位元組資料是否為12,如果不是,繼續等待,否則列印顯示,並取消和刪除共享記憶體。
vmuser@vmuser-virtual-machine:
~/workspace/test$ cat read.c
#include
#include
#include
#include
#include
#include
#include
#define shmsize 10
//共享記憶體大小,10 位元組
#define shmname "shmtest"
//共享記憶體名稱
intmain()
/*對映共享記憶體*/
ptr =
mmap
(null
, shmsize, prot_read | prot_write, map_shared, fd,0)
;if(ptr == map_failed)
/* 設定共享記憶體大小 */
ftruncate
(fd, shmsize)
;while
(*ptr !=
0x12
)printf
("ptr : %d\n"
,*ptr)
;//資料是12,列印顯示
munmap
(ptr, shmsize)
;//取消記憶體對映
shm_unlink
(shmname)
;//刪除共享記憶體
return0;
}
下圖為執行結果截圖,共享記憶體的讀程序先在後台執行,它迴圈等待寫程序對共享記憶體做修改。當寫程序完成修改後,讀程序將檢測到共享記憶體單元的值發生了變化,然後列印出來並退出。
vmuser@vmuser-virtual-machine:
~/workspace/test$ gcc read.c -o read -lrt
vmuser@vmuser-virtual-machine:
~/workspace/test$ gcc write.c -o write -lrt
vmuser@vmuser-virtual-machine:
~/workspace/test$ .
/read &[1
]3752
vmuser@vmuser-virtual-machine:
~/workspace/test$ .
/write
vmuser@vmuser-virtual-machine:
~/workspace/test$ ptr :18[
1]+ done .
/read
vmuser@vmuser-virtual-machine:
~/workspace/test$
POSIX共享記憶體
共享記憶體是最快的可用ipc形式。它允許多個不相關 無親緣關係 的程序去訪問同一部分邏輯記憶體。如果需要在兩個程序之間傳輸資料,共享記憶體將是一種效率極高的解決方案。一旦這樣的記憶體區對映到共享它的程序的位址空間,這些程序間資料的傳輸就不再涉及核心。這樣就可以減少系統呼叫時間,提高程式效率。共享記憶...
Posix共享記憶體區
1 概述 posix提供了兩種在無親緣關係程序間共享記憶體區的方法 者兩種方法多需要呼叫mmap,差別在於作為mmap的引數之一的描述符的獲取手段。2 posix共享記憶體區物件 posix共享記憶體區涉及以下兩個步驟要求 1 指定乙個名字引數呼叫shm open,以建立乙個新的共享記憶體區物件或開...
Posix共享記憶體區
posix提供了兩種在無親緣關係程序間共享記憶體區的方法 2 共享記憶體區物件 先有shm open開啟乙個posix ipc名字 也可以是檔案系統中的乙個路徑名 然後呼叫mmap將返回的描述符對映到當前程序的位址空間。者兩種方法多需要呼叫mmap,差別在於作為mmap的引數之一的描述符的獲取手段。...