linux open 头文件_linux下通过共享内存和mmap实现进程间通讯
前言
最近在學(xué)習(xí)GNU/Linux內(nèi)核,看到mmap的時(shí)候書上說:
mmap/munmap接口函數(shù)是用戶最常用的兩個(gè)系統(tǒng)調(diào)用接口,無論是在用戶程序中分配內(nèi)存、讀寫大文件、鏈接動(dòng)態(tài)庫(kù)文件,還是多進(jìn)程間共享內(nèi)存,都可以看到mmap/munmap的身影。
這句話說的很正確,雖然我們?nèi)粘]有直接使用mmap,但是其實(shí)我們都間接地使用了mmap/mumap函數(shù)。
舉個(gè)例子,我們使用動(dòng)態(tài)鏈接庫(kù)的時(shí)候,我們都知道,動(dòng)態(tài)鏈接不會(huì)把動(dòng)態(tài)庫(kù)中的代碼整合到目標(biāo)文件中,相反,動(dòng)態(tài)庫(kù)跟目標(biāo)文件獨(dú)立。
那為什么運(yùn)行時(shí),程序能夠獲得指定的符號(hào)鏈接?這正是mmap的力量,程序運(yùn)行時(shí),他將保存在物理內(nèi)存的動(dòng)態(tài)庫(kù)的內(nèi)容(如果物理內(nèi)存中沒有,則先加載如內(nèi)存)映射到自身的進(jìn)程地址空間,這樣符號(hào)所對(duì)應(yīng)的指令數(shù)據(jù)便存在了。
(通過ldd可獲取所依賴的動(dòng)態(tài)庫(kù),Linux怎么獲取到的,我懷疑跟ELF文件格式有關(guān),待解答)
mmap
mmap是內(nèi)存映射文件的方法
mmap將一個(gè)文件或者其它對(duì)象映射進(jìn)內(nèi)存。mmap在用戶空間映射調(diào)用系統(tǒng)中作用很大。
mmap()必須以PAGE_SIZE為單位進(jìn)行映射,而內(nèi)存也只能以頁(yè)為單位進(jìn)行映射,若要映射非PAGE_SIZE整數(shù)倍的地址范圍,要先進(jìn)行內(nèi)存對(duì)齊,強(qiáng)行以PAGE_SIZE的倍數(shù)大小進(jìn)行映射。
頭文件
函數(shù)原型
void* mmap(void* addr, size_t length,int prot,int flags,int fd,off_t offset); int munmap(void* start,size_t length);
- addr: 用于指定映射到進(jìn)程地址的起始地址,為了應(yīng)用程序的可移植性,一般設(shè)為nullptr;
- length: 表示映射到進(jìn)程地址空間的大小;
- prot: 表示設(shè)置內(nèi)存映射區(qū)域的讀寫屬性等;
- flags: 用于設(shè)置內(nèi)存映射的屬性,例如共享映射、私有映射、匿名映射等;
- fd: 文件句柄,如果不是文件映射,則置為0;
- offset: 文件映射時(shí)的文件偏移量。
重復(fù)一遍:由于GNU/Linux中,內(nèi)存分配是以頁(yè)為單位的,所以length長(zhǎng)度不足1頁(yè)(默認(rèn)4KB),則按1頁(yè)來處理。
prot參數(shù)detail:
flags參數(shù)detail:
共享內(nèi)存
共享內(nèi)存Shared Memory,顧名思義就是允許兩個(gè)不相關(guān)的進(jìn)程訪問同一個(gè)邏輯內(nèi)存,共享內(nèi)存是兩個(gè)正在運(yùn)行的進(jìn)程之間共享和傳遞數(shù)據(jù)的一種非常有效的方式。
具體來說,共享內(nèi)存就是一段真實(shí)存在的物理內(nèi)存,不同進(jìn)程通過訪問和修改該段物理內(nèi)存,最終達(dá)到共享內(nèi)存的目的。
PS: 共享內(nèi)存不提供數(shù)據(jù)同步機(jī)制,如一個(gè)進(jìn)程在寫過程中,另一個(gè)進(jìn)程可以進(jìn)行讀操作和寫操作,所以需要通過信號(hào)量來解決同步問題。
創(chuàng)建共享內(nèi)存
函數(shù)介紹
函數(shù)原型如下:
#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()創(chuàng)建并打開一個(gè)新的或現(xiàn)有的POSIX共享內(nèi)存對(duì)象。POSIX共享內(nèi)存對(duì)象實(shí)際上是一個(gè)句柄,它可以被與mmap共享內(nèi)存相同區(qū)域的無關(guān)進(jìn)程使用。
shm_unlink()函數(shù)的作用是:刪除先前由shm_open()創(chuàng)建的對(duì)象。
函數(shù)用法
int fd = shm_open("/shm01", O_CREAT | O_RDWR, 0777);當(dāng)oflag使用O_CREAT時(shí),mode表示創(chuàng)建文件時(shí)的權(quán)限,權(quán)限寫法跟命令chmod一樣(https://www.runoob.com/linux/linux-comm-chmod.html)。
open與shm_open區(qū)別
或許你會(huì)問:如果是創(chuàng)建一個(gè)文件何必使用shm_open呢?為什么不使用open?
理論上來說兩個(gè)方法可以相互替換。
但是,很重要的一點(diǎn)是:shm_open會(huì)將文件創(chuàng)建在/dev/shm目錄下,該目錄下掛載的文件系統(tǒng)格式是tmpfs,該目錄下的文件也只存儲(chǔ)在內(nèi)存(主存)中。如果你使用open方法在該目錄下創(chuàng)建和打開文件其實(shí)兩者就沒有本質(zhì)區(qū)別了。
如圖所示,/dev/shm是tmpfs文件系統(tǒng)
進(jìn)程間通訊實(shí)例
本測(cè)試用例需要依賴googletest測(cè)試框架,當(dāng)然讀者可以通過分別建立兩個(gè)項(xiàng)目來實(shí)現(xiàn)下述實(shí)例;
實(shí)例原理
如圖所示,共享內(nèi)存創(chuàng)建后保存在真實(shí)的物理內(nèi)存中,通過mmap函數(shù)我們將該物理內(nèi)存地址映射到進(jìn)程地址空間中,最終實(shí)現(xiàn)操作共享內(nèi)存的功能。
實(shí)例功能
服務(wù)端:創(chuàng)建共享內(nèi)存,并將內(nèi)存映射到進(jìn)程地址空間中,然后進(jìn)行定時(shí)修改內(nèi)存內(nèi)容。
客戶端:映射共享內(nèi)存到進(jìn)程地址空間中,定時(shí)獲取內(nèi)存內(nèi)容。
實(shí)例代碼
服務(wù)端代碼
#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內(nèi)存 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); // 關(guān)閉映射 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);}執(zhí)行結(jié)果
開頭的z是之前保存在共享內(nèi)存中的數(shù)據(jù)
可以看到客戶端輸出了英語(yǔ)字母。
遇到的問題
答:在編譯時(shí)鏈接rt庫(kù)
答:鏈接pthread庫(kù)
總結(jié)
本篇文章,我們知道了共享內(nèi)存,通過共享內(nèi)存和mmap我們能很輕易地完成進(jìn)程間通訊(IPC Inter-Process Communication),進(jìn)程間的semaphore(信號(hào)量)實(shí)現(xiàn)方式也是通過mmap和共享變量實(shí)現(xiàn)的。
文章出處:https://my.oschina.net/StupidZhe/blog/4647178
總結(jié)
以上是生活随笔為你收集整理的linux open 头文件_linux下通过共享内存和mmap实现进程间通讯的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 内存分析_python内存
- 下一篇: 公众号 接收规则 消息_微信公众平台 发