Linux系统编程---5(共享存储映射,存储映射I/O,mmap函数,父子进程间通信,匿名映射)
共享存儲映射
文件進程間通信
使用文件也可以完成 IPC,理論依據是,fork 后,父子進程共享文件描述符。也就共享打開的文件。
編程:父子進程共享打開的文件。借助文件進行進程間通信。
測試代碼
思考,無血緣關系的進程可以打開同一個文件進行通信嗎?為什么?
可以,,無血緣關系的進程也可以打開同一個文件進行通信,方法一樣,因為這些進程打開的是同一個進程。其實在打開文件時(調用open時),操作系統內核就調用了mmap。因為一個文件只有一個文件結構體(FILE),打開時位于內核,被打開這個文件的多個進程共享。
存儲映射 I/O
存儲映射 I/O(Memory-mappedI/O) 使一個磁盤文件與存儲空間中的一個緩沖區相映射。于是當從緩沖區中取 數據,就相當于讀文件中的相應字節。于此類似,將數據存入緩沖區,則相應的字節就自動寫入文件。這樣,就可 在不適用 read 和 write 函數的情況下,使用地址(指針)完成 I/O 操作。
使用這種方法,首先應通知內核,將一個指定文件映射到存儲區域中。這個映射工作可以通過 mmap 函數來實
現。
mmap 函數
void* mmap(void* adrr,size_t length,int prot,int flags,int fd,off_toffset); 返回:成功:返回創建的映射區首地址;失敗:MAP_FAILED 宏
參數:
addr: 建立映射區的首地址,由 Linux 內核指定。使用時,直接傳遞 NULL
length: 欲創建映射區的大小
prot: 映射區權限 PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE
flags: 標志位參數(常用于設定更新物理區域、設置共享、創建匿名映射區) MAP_SHARED: 會將映射區所做的操作反映到物理設備(磁盤)上。 MAP_PRIVATE: 映射區所做的修改不會反映到物理設備。
fd: 用來建立映射區的文件描述符
offset: 映射文件的偏移(4k 的整數倍)
munmap 函數
同 malloc 函數申請內存空間類似的,mmap 建立的映射區在使用結束后也應調用類似 free 的函數來釋放。 int munmap(void *addr,size_t length); 成功:0; 失敗:-1
mmap 注意事項
思考:
答:可以,但新CREATE出來的文件不行,必須要有實際的大小
答:不行,創建映射區的權限小于等于打開文件的權限,映射區創建的過程中存在一次讀文件操作權限不足。
答: 沒有影響,文件描述符是操作文件的句柄,有映射區了,就是地址的方式操作,所以文件描述符就沒意義了。
答:不行,偏移量必須是一頁的大小(4k)
答:不行,釋放映射區可能會失敗,只有創建映射區的地址和釋放時的地址要是同一個地址
答:不能,釋放映射區的時候要傳首地址和映射區大小給munmap,但++后首地址就不是創建時的首地址,只有創建映射區的地址和釋放時的地址要是同一個地址
答:返回值必須檢查,空間不能為0,文件大小和映射區要匹配等等情況下會失敗
總結
mmap 父子進程通信
父子等有血緣關系的進程之間也可以通過 mmap 建立的映射區來完成數據通信。但相應的要在創建映射區的時 候指定對應的標志位參數 flags:
編程:父進程創建映射區,然后 fork 子進程,子進程修改映射區內容,而后,父進程讀取映射區內容,查驗是 否共享
結論:父子進程共享:
匿名映射
通過使用我們發現,使用映射區來完成文件讀寫操作十分方便,父子進程間通信也較容易。但缺陷是,每次創 建映射區一定要依賴一個文件才能實現。通常為了建立映射區要 open 一個 temp 文件,創建好了再 unlink、close 掉,比較麻煩。 可以直接使用匿名映射來代替。其實 Linux 系統給我們提供了創建匿名映射區的方法,無需依賴一 個文件即可創建映射區。同樣需要借助標志位參數 flags 來指定。
使用 MAP_ANONYMOUS(或 MAP_ANON),
"4"隨意舉例,該位置表大小,可依實際需要填寫。
需注意的是,MAP_ANONYMOUS 和 MAP_ANON 這兩個宏是 Linux 操作系統特有的宏。在類 Unix 系統中如無該 宏定義,可使用如下兩步來完成匿名映射區的建立。
示例代碼:
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<fcntl.h> #include<sys/mman.h> #include<sys/wait.h>int var=100;int main(void ) {int *p; pid_t pid;//不使用文件參數傳-1 p=(int *)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);//對映射區>各自獨占if(p==MAP_FAILED){ //不是p==NULL時出錯perror("mmap,error"); exit(1);} //完成數據傳遞pid=fork();if(pid==0){*p=2000;var=1000;printf("child,*p=%d,var = %d\n",*p,var);}else{sleep(1);printf("parent,*p = %d,var = =%d\n",*p,var);wait(NULL);int ret= munmap(p,4); if(ret==-1){perror("munmap error");exit(1);}}return 0; }
Linux下這兩個文件無大小
第一個文件好比聚寶盆,可以隨意映射
第二個文件,一般錯誤洗腦洗重定向到這個文件中
mmap 無血緣關系進程間通信
實質上 mmap 是內核借助文件幫我們創建了一個映射區,多個進程之間利用該映射區完成數據傳遞。由于內核 空間多進程共享,因此無血緣關系的進程間也可以使用 mmap 來完成通信。只要設置相應的標志位參數 flags 即可。 若想實現共享,當然應該使用 MAP_SHARED 了。
讀數據
寫數據
/* * 非血緣關系之間的通信*/ #include<stdio.h> #include<sys/stat.h> #include<sys/types.h> #include<fcntl.h> #include<unistd.h> #include<stdlib.h> #include<sys/mman.h> #include<string.h>struct STU{int id;char name[20];char sex; };void sys_err(char *str) {perror(str);exit(1); }int main(int argc,char *argv[]) {int fd;struct STU student={10,"xiaoming",'m'};char *mm;if(argc<2){printf("./a.out file_shared\n");exit(-1);}fd = open(argv[1],O_RDWR | O_CREAT,0644);ftruncate(fd,sizeof(student));mm = mmap(NULL,sizeof(student),PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);if(mm == MAP_FAILED)sys_err("mmap"); close(fd);while(1){memcpy(mm,&student,sizeof(student));student.id++; //循環向內存復制sleep(1);}munmap(mm,sizeof(student));return 0; }
總結
以上是生活随笔為你收集整理的Linux系统编程---5(共享存储映射,存储映射I/O,mmap函数,父子进程间通信,匿名映射)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DNF我用飞机秒杀加瞬移下图,竟然没有他
- 下一篇: Linux下文件的多进程拷贝