Linux系统编程---5(共享存储映射,存储映射I/O,mmap函数,父子进程间通信,匿名映射)
共享存儲(chǔ)映射
文件進(jìn)程間通信
使用文件也可以完成 IPC,理論依據(jù)是,fork 后,父子進(jìn)程共享文件描述符。也就共享打開的文件。
編程:父子進(jìn)程共享打開的文件。借助文件進(jìn)行進(jìn)程間通信。
測試代碼
思考,無血緣關(guān)系的進(jìn)程可以打開同一個(gè)文件進(jìn)行通信嗎?為什么?
可以,,無血緣關(guān)系的進(jìn)程也可以打開同一個(gè)文件進(jìn)行通信,方法一樣,因?yàn)檫@些進(jìn)程打開的是同一個(gè)進(jìn)程。其實(shí)在打開文件時(shí)(調(diào)用open時(shí)),操作系統(tǒng)內(nèi)核就調(diào)用了mmap。因?yàn)橐粋€(gè)文件只有一個(gè)文件結(jié)構(gòu)體(FILE),打開時(shí)位于內(nèi)核,被打開這個(gè)文件的多個(gè)進(jìn)程共享。
存儲(chǔ)映射 I/O
存儲(chǔ)映射 I/O(Memory-mappedI/O) 使一個(gè)磁盤文件與存儲(chǔ)空間中的一個(gè)緩沖區(qū)相映射。于是當(dāng)從緩沖區(qū)中取 數(shù)據(jù),就相當(dāng)于讀文件中的相應(yīng)字節(jié)。于此類似,將數(shù)據(jù)存入緩沖區(qū),則相應(yīng)的字節(jié)就自動(dòng)寫入文件。這樣,就可 在不適用 read 和 write 函數(shù)的情況下,使用地址(指針)完成 I/O 操作。
使用這種方法,首先應(yīng)通知內(nèi)核,將一個(gè)指定文件映射到存儲(chǔ)區(qū)域中。這個(gè)映射工作可以通過 mmap 函數(shù)來實(shí)
現(xiàn)。
mmap 函數(shù)
void* mmap(void* adrr,size_t length,int prot,int flags,int fd,off_toffset); 返回:成功:返回創(chuàng)建的映射區(qū)首地址;失敗:MAP_FAILED 宏
參數(shù):
addr: 建立映射區(qū)的首地址,由 Linux 內(nèi)核指定。使用時(shí),直接傳遞 NULL
length: 欲創(chuàng)建映射區(qū)的大小
prot: 映射區(qū)權(quán)限 PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE
flags: 標(biāo)志位參數(shù)(常用于設(shè)定更新物理區(qū)域、設(shè)置共享、創(chuàng)建匿名映射區(qū)) MAP_SHARED: 會(huì)將映射區(qū)所做的操作反映到物理設(shè)備(磁盤)上。 MAP_PRIVATE: 映射區(qū)所做的修改不會(huì)反映到物理設(shè)備。
fd: 用來建立映射區(qū)的文件描述符
offset: 映射文件的偏移(4k 的整數(shù)倍)
munmap 函數(shù)
同 malloc 函數(shù)申請(qǐng)內(nèi)存空間類似的,mmap 建立的映射區(qū)在使用結(jié)束后也應(yīng)調(diào)用類似 free 的函數(shù)來釋放。 int munmap(void *addr,size_t length); 成功:0; 失敗:-1
mmap 注意事項(xiàng)
思考:
答:可以,但新CREATE出來的文件不行,必須要有實(shí)際的大小
答:不行,創(chuàng)建映射區(qū)的權(quán)限小于等于打開文件的權(quán)限,映射區(qū)創(chuàng)建的過程中存在一次讀文件操作權(quán)限不足。
答: 沒有影響,文件描述符是操作文件的句柄,有映射區(qū)了,就是地址的方式操作,所以文件描述符就沒意義了。
答:不行,偏移量必須是一頁的大小(4k)
答:不行,釋放映射區(qū)可能會(huì)失敗,只有創(chuàng)建映射區(qū)的地址和釋放時(shí)的地址要是同一個(gè)地址
答:不能,釋放映射區(qū)的時(shí)候要傳首地址和映射區(qū)大小給munmap,但++后首地址就不是創(chuàng)建時(shí)的首地址,只有創(chuàng)建映射區(qū)的地址和釋放時(shí)的地址要是同一個(gè)地址
答:返回值必須檢查,空間不能為0,文件大小和映射區(qū)要匹配等等情況下會(huì)失敗
總結(jié)
mmap 父子進(jìn)程通信
父子等有血緣關(guān)系的進(jìn)程之間也可以通過 mmap 建立的映射區(qū)來完成數(shù)據(jù)通信。但相應(yīng)的要在創(chuàng)建映射區(qū)的時(shí) 候指定對(duì)應(yīng)的標(biāo)志位參數(shù) flags:
編程:父進(jìn)程創(chuàng)建映射區(qū),然后 fork 子進(jìn)程,子進(jìn)程修改映射區(qū)內(nèi)容,而后,父進(jìn)程讀取映射區(qū)內(nèi)容,查驗(yàn)是 否共享
結(jié)論:父子進(jìn)程共享:
匿名映射
通過使用我們發(fā)現(xiàn),使用映射區(qū)來完成文件讀寫操作十分方便,父子進(jìn)程間通信也較容易。但缺陷是,每次創(chuàng) 建映射區(qū)一定要依賴一個(gè)文件才能實(shí)現(xiàn)。通常為了建立映射區(qū)要 open 一個(gè) temp 文件,創(chuàng)建好了再 unlink、close 掉,比較麻煩。 可以直接使用匿名映射來代替。其實(shí) Linux 系統(tǒng)給我們提供了創(chuàng)建匿名映射區(qū)的方法,無需依賴一 個(gè)文件即可創(chuàng)建映射區(qū)。同樣需要借助標(biāo)志位參數(shù) flags 來指定。
使用 MAP_ANONYMOUS(或 MAP_ANON),
"4"隨意舉例,該位置表大小,可依實(shí)際需要填寫。
需注意的是,MAP_ANONYMOUS 和 MAP_ANON 這兩個(gè)宏是 Linux 操作系統(tǒng)特有的宏。在類 Unix 系統(tǒng)中如無該 宏定義,可使用如下兩步來完成匿名映射區(qū)的建立。
示例代碼:
#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;//不使用文件參數(shù)傳-1 p=(int *)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);//對(duì)映射區(qū)>各自獨(dú)占if(p==MAP_FAILED){ //不是p==NULL時(shí)出錯(cuò)perror("mmap,error"); exit(1);} //完成數(shù)據(jù)傳遞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下這兩個(gè)文件無大小
第一個(gè)文件好比聚寶盆,可以隨意映射
第二個(gè)文件,一般錯(cuò)誤洗腦洗重定向到這個(gè)文件中
mmap 無血緣關(guān)系進(jìn)程間通信
實(shí)質(zhì)上 mmap 是內(nèi)核借助文件幫我們創(chuàng)建了一個(gè)映射區(qū),多個(gè)進(jìn)程之間利用該映射區(qū)完成數(shù)據(jù)傳遞。由于內(nèi)核 空間多進(jìn)程共享,因此無血緣關(guān)系的進(jìn)程間也可以使用 mmap 來完成通信。只要設(shè)置相應(yīng)的標(biāo)志位參數(shù) flags 即可。 若想實(shí)現(xiàn)共享,當(dāng)然應(yīng)該使用 MAP_SHARED 了。
讀數(shù)據(jù)
寫數(shù)據(jù)
/* * 非血緣關(guān)系之間的通信*/ #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++; //循環(huán)向內(nèi)存復(fù)制sleep(1);}munmap(mm,sizeof(student));return 0; }
總結(jié)
以上是生活随笔為你收集整理的Linux系统编程---5(共享存储映射,存储映射I/O,mmap函数,父子进程间通信,匿名映射)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DNF我用飞机秒杀加瞬移下图,竟然没有他
- 下一篇: lg电视屏幕出现一横条无虚线声音