linux open 头文件_linux下通过共享内存和mmap实现进程间通讯
前言
最近在學習GNU/Linux內核,看到mmap的時候書上說:
mmap/munmap接口函數是用戶最常用的兩個系統調用接口,無論是在用戶程序中分配內存、讀寫大文件、鏈接動態庫文件,還是多進程間共享內存,都可以看到mmap/munmap的身影。
這句話說的很正確,雖然我們日常沒有直接使用mmap,但是其實我們都間接地使用了mmap/mumap函數。
舉個例子,我們使用動態鏈接庫的時候,我們都知道,動態鏈接不會把動態庫中的代碼整合到目標文件中,相反,動態庫跟目標文件獨立。
那為什么運行時,程序能夠獲得指定的符號鏈接?這正是mmap的力量,程序運行時,他將保存在物理內存的動態庫的內容(如果物理內存中沒有,則先加載如內存)映射到自身的進程地址空間,這樣符號所對應的指令數據便存在了。
(通過ldd可獲取所依賴的動態庫,Linux怎么獲取到的,我懷疑跟ELF文件格式有關,待解答)
mmap
mmap是內存映射文件的方法
mmap將一個文件或者其它對象映射進內存。mmap在用戶空間映射調用系統中作用很大。
mmap()必須以PAGE_SIZE為單位進行映射,而內存也只能以頁為單位進行映射,若要映射非PAGE_SIZE整數倍的地址范圍,要先進行內存對齊,強行以PAGE_SIZE的倍數大小進行映射。
頭文件
函數原型
void* mmap(void* addr, size_t length,int prot,int flags,int fd,off_t offset); int munmap(void* start,size_t length);
- addr: 用于指定映射到進程地址的起始地址,為了應用程序的可移植性,一般設為nullptr;
- length: 表示映射到進程地址空間的大小;
- prot: 表示設置內存映射區域的讀寫屬性等;
- flags: 用于設置內存映射的屬性,例如共享映射、私有映射、匿名映射等;
- fd: 文件句柄,如果不是文件映射,則置為0;
- offset: 文件映射時的文件偏移量。
重復一遍:由于GNU/Linux中,內存分配是以頁為單位的,所以length長度不足1頁(默認4KB),則按1頁來處理。
prot參數detail:
flags參數detail:
共享內存
共享內存Shared Memory,顧名思義就是允許兩個不相關的進程訪問同一個邏輯內存,共享內存是兩個正在運行的進程之間共享和傳遞數據的一種非常有效的方式。
具體來說,共享內存就是一段真實存在的物理內存,不同進程通過訪問和修改該段物理內存,最終達到共享內存的目的。
PS: 共享內存不提供數據同步機制,如一個進程在寫過程中,另一個進程可以進行讀操作和寫操作,所以需要通過信號量來解決同步問題。
創建共享內存
函數介紹
函數原型如下:
#include #include /* For mode constants */#include /* For O_* constants */int shm_open(const char *name, int oflag, mode_t mode);int shm_unlink(const char *name);Link with -lrt.shm_open()創建并打開一個新的或現有的POSIX共享內存對象。POSIX共享內存對象實際上是一個句柄,它可以被與mmap共享內存相同區域的無關進程使用。
shm_unlink()函數的作用是:刪除先前由shm_open()創建的對象。
函數用法
int fd = shm_open("/shm01", O_CREAT | O_RDWR, 0777);當oflag使用O_CREAT時,mode表示創建文件時的權限,權限寫法跟命令chmod一樣(https://www.runoob.com/linux/linux-comm-chmod.html)。
open與shm_open區別
或許你會問:如果是創建一個文件何必使用shm_open呢?為什么不使用open?
理論上來說兩個方法可以相互替換。
但是,很重要的一點是:shm_open會將文件創建在/dev/shm目錄下,該目錄下掛載的文件系統格式是tmpfs,該目錄下的文件也只存儲在內存(主存)中。如果你使用open方法在該目錄下創建和打開文件其實兩者就沒有本質區別了。
如圖所示,/dev/shm是tmpfs文件系統
進程間通訊實例
本測試用例需要依賴googletest測試框架,當然讀者可以通過分別建立兩個項目來實現下述實例;
實例原理
如圖所示,共享內存創建后保存在真實的物理內存中,通過mmap函數我們將該物理內存地址映射到進程地址空間中,最終實現操作共享內存的功能。
實例功能
服務端:創建共享內存,并將內存映射到進程地址空間中,然后進行定時修改內存內容。
客戶端:映射共享內存到進程地址空間中,定時獲取內存內容。
實例代碼
服務端代碼
#include #include #include #include TEST(shm_test, server) { int fd = shm_open("/shm01", O_CREAT | O_RDWR, 0777); // int fd = open("/dev/shm/shm01", O_CREAT | O_RDWR); if (fd < 0) { std::cout << "error to create or open" << std::endl; return; } std::cout << "create or open ok" << std::endl; ftruncate(fd, 4096);// 分配4KB內存 char *ptr = (char *)mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); close(fd); char a[] = "00"; for (char k = 0; k < 26; ++k) { memset(a, 'a' + k, 1 *sizeof(char)); strcpy(ptr, a); sleep(1); } strcpy(ptr, a); mumap((void *)ptr, 4096); // 關閉映射 exit(0);}客戶端代碼
#include #include #include #include TEST(test, client) { int fd = shm_open("/shm01", O_RDWR, 0777); // int fd = open("/dev/shm/shm01", O_CREAT | O_RDWR); if (fd < 0) { std::cout << "error to open" << std::endl; return; } char *ptr = (char *)mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); close(fd); while(true) { std::cout << ptr << std::endl; sleep(1); } exit(0);}執行結果
開頭的z是之前保存在共享內存中的數據
可以看到客戶端輸出了英語字母。
遇到的問題
答:在編譯時鏈接rt庫
答:鏈接pthread庫
總結
本篇文章,我們知道了共享內存,通過共享內存和mmap我們能很輕易地完成進程間通訊(IPC Inter-Process Communication),進程間的semaphore(信號量)實現方式也是通過mmap和共享變量實現的。
文章出處:https://my.oschina.net/StupidZhe/blog/4647178
總結
以上是生活随笔為你收集整理的linux open 头文件_linux下通过共享内存和mmap实现进程间通讯的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 内存分析_python内存
- 下一篇: linux运行好麻烦,解析用Linux非