日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux系统编程---5(共享存储映射,存储映射I/O,mmap函数,父子进程间通信,匿名映射)

發(fā)布時間:2023/11/30 linux 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux系统编程---5(共享存储映射,存储映射I/O,mmap函数,父子进程间通信,匿名映射) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

共享存儲映射

文件進程間通信

使用文件也可以完成 IPC,理論依據(jù)是,fork 后,父子進程共享文件描述符。也就共享打開的文件。
編程:父子進程共享打開的文件。借助文件進行進程間通信。
測試代碼

/*** 父子進程共享打開的文件描述符----使用文件完成進程間通信**/#include<stdio.h> #include<unistd.h> #include<string.h> #include<stdlib.h> #include<fcntl.h> #include<sys/wait.h>int main(void) {int fd1,fd2;pid_t pid;char buf[1024]; char *str="----------test for shared fd in parent child process -----\n";pid=fork();if(pid<0){perror("fork error");exit(1);}else if(pid==0){fd1=open("test.txt",O_RDWR);if(fd1<0){perror("open error");exit(1);} write(fd1,str,strlen(str));printf("child wrote over...\n");}else{fd2=open("test.txt",O_RDWR);if(fd2<0){perror("open error");exit(1);}sleep(1); //保證子進程寫入數(shù)據(jù)int len =read(fd2,buf,sizeof(buf));write(STDOUT_FILENO,buf,len);wait(NULL);//回收防止僵尸進程}return 0; }

思考,無血緣關系的進程可以打開同一個文件進行通信嗎?為什么?
可以,,無血緣關系的進程也可以打開同一個文件進行通信,方法一樣,因為這些進程打開的是同一個進程。其實在打開文件時(調用open時),操作系統(tǒng)內核就調用了mmap。因為一個文件只有一個文件結構體(FILE),打開時位于內核,被打開這個文件的多個進程共享。

存儲映射 I/O

存儲映射 I/O(Memory-mappedI/O) 使一個磁盤文件與存儲空間中的一個緩沖區(qū)相映射。于是當從緩沖區(qū)中取 數(shù)據(jù),就相當于讀文件中的相應字節(jié)。于此類似,將數(shù)據(jù)存入緩沖區(qū),則相應的字節(jié)就自動寫入文件。這樣,就可 在不適用 read 和 write 函數(shù)的情況下,使用地址(指針)完成 I/O 操作。
使用這種方法,首先應通知內核,將一個指定文件映射到存儲區(qū)域中。這個映射工作可以通過 mmap 函數(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 內核指定。使用時,直接傳遞 NULL

  • length: 欲創(chuàng)建映射區(qū)的大小

  • prot: 映射區(qū)權限 PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE

  • flags: 標志位參數(shù)(常用于設定更新物理區(qū)域、設置共享、創(chuàng)建匿名映射區(qū)) MAP_SHARED: 會將映射區(qū)所做的操作反映到物理設備(磁盤)上。 MAP_PRIVATE: 映射區(qū)所做的修改不會反映到物理設備。

  • fd: 用來建立映射區(qū)的文件描述符

  • offset: 映射文件的偏移(4k 的整數(shù)倍)

    #include<stdio.h>#include<fcntl.h>#include<unistd.h>#include<string.h>#include<stdlib.h>#include<sys/mman.h>int main(void){int len,ret;char *p=NULL;int fd = open("mytest.txt",O_CREAT|O_RDWR,0644);if(fd<0){perror("open error");exit(1);} //確定文件大小len = ftruncate(fd,4);if(len == -1){perror("ftruncate error:");exit(1);} p = mmap(NULL, 4 , PROT_READ|PROT_WRITE , MAP_SHARED, fd, 0); if(p == MAP_FAILED){perror("mmap error:");exit(1);} strcpy(p,"abc");//寫數(shù)據(jù)ret = munmap(p,4);//釋放映射區(qū) if(ret==-1){perror("munmap error:");exit(1);} close(fd);return 0;}
  • munmap 函數(shù)

    同 malloc 函數(shù)申請內存空間類似的,mmap 建立的映射區(qū)在使用結束后也應調用類似 free 的函數(shù)來釋放。 int munmap(void *addr,size_t length); 成功:0; 失敗:-1

    mmap 注意事項

    思考:

  • 可以 open 的時候 O_CREAT 一個新文件來創(chuàng)建映射區(qū)嗎?
    答:可以,但新CREATE出來的文件不行,必須要有實際的大小
  • 如果 open 時 O_RDONLY,mmap 時 PROT 參數(shù)指定 PROT_READ|PROT_WRITE 會怎樣?
    答:不行,創(chuàng)建映射區(qū)的權限小于等于打開文件的權限,映射區(qū)創(chuàng)建的過程中存在一次讀文件操作權限不足。
  • 文件描述符先關閉,對 mmap 映射有沒有影響?
    答: 沒有影響,文件描述符是操作文件的句柄,有映射區(qū)了,就是地址的方式操作,所以文件描述符就沒意義了。
  • 如果文件偏移量為 1000 會怎樣?
    答:不行,偏移量必須是一頁的大小(4k)
  • 對 mem 越界操作會怎樣?
    答:不行,釋放映射區(qū)可能會失敗,只有創(chuàng)建映射區(qū)的地址和釋放時的地址要是同一個地址
  • 如果 mem++,munmap 可否成功?
    答:不能,釋放映射區(qū)的時候要傳首地址和映射區(qū)大小給munmap,但++后首地址就不是創(chuàng)建時的首地址,只有創(chuàng)建映射區(qū)的地址和釋放時的地址要是同一個地址
  • mmap 什么情況下會調用失敗? 8. 如果不檢測 mmap 的返回值,會怎樣?
    答:返回值必須檢查,空間不能為0,文件大小和映射區(qū)要匹配等等情況下會失敗
  • 總結

  • 創(chuàng)建映射區(qū)的過程中,隱含著一次對映射文件的讀操作。
  • 當 MAP_SHARED 時,要求:映射區(qū)的權限應 <=文件打開的權限(出于對映射區(qū)的保護)。而 MAP_PRIVATE 則無所謂,因為 mmap 中的權限是對內存的限制。
  • 映射區(qū)的釋放與文件關閉無關。只要映射建立成功,文件可以立即關閉。
  • 特別注意,當映射文件大小為 0 時,不能創(chuàng)建映射區(qū)。所以:用于映射的文件必須要有實際大小!! mmap 使用時常常會出現(xiàn)總線錯誤,通常是由于共享文件存儲空間大小引起的。
  • munmap 傳入的地址一定是 mmap 的返回地址。堅決杜絕指針++操作。
  • 如果文件偏移量必須為 4K 的整數(shù)倍 7. mmap 創(chuàng)建映射區(qū)出錯概率非常高,一定要檢查返回值,確保映射區(qū)建立成功再進行后續(xù)操作。
  • mmap 父子進程通信

    父子等有血緣關系的進程之間也可以通過 mmap 建立的映射區(qū)來完成數(shù)據(jù)通信。但相應的要在創(chuàng)建映射區(qū)的時 候指定對應的標志位參數(shù) flags:

  • MAP_PRIVATE: (私有映射) 父子進程各自獨占映射區(qū);
  • MAP_SHARED: (共享映射) 父子進程共享映射區(qū);
    編程:父進程創(chuàng)建映射區(qū),然后 fork 子進程,子進程修改映射區(qū)內容,而后,父進程讀取映射區(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;int fd;fd=open("temp",O_RDWR|O_CREAT|O_TRUNC,0644);if(fd<0){perror("open error:");exit(1);}unlink("temp"); //刪除臨時文件目錄項,使之具備被釋放條件,所有使用該文>件的進程結束后該文件才釋放ftruncate(fd,4); //創(chuàng)建文件大小p=(int *)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//父子進程共享映射區(qū)// p=(int *)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0);//對映射區(qū)各自獨>占 if(p==MAP_FAILED){ //不是p==NULL時出錯perror("mmap,error"); exit(1);}close(fd); //映射區(qū)建立完畢,即可關閉文件//完成數(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;}

    結論:父子進程共享:

  • 打開的文件
  • mmap 建立的映射區(qū)(但必須要使用 MAP_SHARED)
  • 匿名映射

    通過使用我們發(fā)現(xiàn),使用映射區(qū)來完成文件讀寫操作十分方便,父子進程間通信也較容易。但缺陷是,每次創(chuàng) 建映射區(qū)一定要依賴一個文件才能實現(xiàn)。通常為了建立映射區(qū)要 open 一個 temp 文件,創(chuàng)建好了再 unlink、close 掉,比較麻煩。 可以直接使用匿名映射來代替。其實 Linux 系統(tǒng)給我們提供了創(chuàng)建匿名映射區(qū)的方法,無需依賴一 個文件即可創(chuàng)建映射區(qū)。同樣需要借助標志位參數(shù) flags 來指定。
    使用 MAP_ANONYMOUS(或 MAP_ANON),

    int*p=mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);

    "4"隨意舉例,該位置表大小,可依實際需要填寫。

    需注意的是,MAP_ANONYMOUS 和 MAP_ANON 這兩個宏是 Linux 操作系統(tǒng)特有的宏。在類 Unix 系統(tǒng)中如無該 宏定義,可使用如下兩步來完成匿名映射區(qū)的建立。

  • fd=open("/dev/zero",O_RDWR);
  • p=mmap(NULL,size,PROT_READ|PROT_WRITE,MMAP_SHARED,fd,0);
  • 示例代碼:

    #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);//對映射區(qū)>各自獨占if(p==MAP_FAILED){ //不是p==NULL時出錯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下這兩個文件無大小

    第一個文件好比聚寶盆,可以隨意映射
    第二個文件,一般錯誤洗腦洗重定向到這個文件中

    mmap 無血緣關系進程間通信

    實質上 mmap 是內核借助文件幫我們創(chuàng)建了一個映射區(qū),多個進程之間利用該映射區(qū)完成數(shù)據(jù)傳遞。由于內核 空間多進程共享,因此無血緣關系的進程間也可以使用 mmap 來完成通信。只要設置相應的標志位參數(shù) flags 即可。 若想實現(xiàn)共享,當然應該使用 MAP_SHARED 了。

    讀數(shù)據(jù)

    /** 非血緣關系進程間通信*/ #include<stdio.h> #include<sys/stat.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; };//出錯處理函數(shù) void sys_err(char *str) {perror(str);exit(-1); }int main(int argc,char *argv[]) {int fd; struct STU student;struct STU *mm;if(argc<2){printf("./a.out file_shared\n");exit(-1);} fd=open(argv[1],O_RDONLY);if(fd == -1) sys_err("open error");mm = mmap(NULL,sizeof(student),PROT_READ,MAP_SHARED,fd,0);if(mm == MAP_FAILED)sys_err("mmap error");close(fd);while(1){ //讀進程 printf("id=%d\tname=%s\t%c\n",mm->id,mm->name,mm->sex);sleep(2);}munmap(mm,sizeof(student));return 0; }

    寫數(shù)據(jù)

    /* * 非血緣關系之間的通信*/ #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)向內存復制sleep(1);}munmap(mm,sizeof(student));return 0; }



    總結

    以上是生活随笔為你收集整理的Linux系统编程---5(共享存储映射,存储映射I/O,mmap函数,父子进程间通信,匿名映射)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。