Linux進程通信之mmap

mmap()函數:

void *mmap(void* addr,size_t length,int port,int flags,int fd,off_t offset);

返回:成功:返回創建的映射區首地址;失敗:MAP_FAILED 宏

參數:

?????? addr:????? 建立映射區的首地址,由linux內核決定。使用時直接傳遞NULL;

?????? length:?? 欲創建映射區的大小

?????? port:??? 映射區權限PROT _READ、PROT_WRITE 、PROT _READ|PROTWRITE

?????? flags:?? 標志位參數(常用于設定更新物理區域、設置共享、創建匿名映射區)

???????????????????? MAP_SHARED:???? 會將映射區所做的操作反射到物理設備上

???????????????????? MAP_PRIVATE:???? 映射區所作的修改不會反映到物理設備。

?????? fd:?????? 用來建立映射區的文件描述符

?????? offset:? 映射文件的偏移(4K的整數倍)

/***
mmap.c
***/
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/mman.h>int main()
{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(-1 == len){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");ret = munmap(p,4);if(-1 == ret){perror("mmap error:");exit(1);} close(fd);return 0;
}

運行結果:

ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc mmap.c -o mmap

ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./mmap

ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ cat mytest.txt

abc

mmap在使用過程中注意以下事項:

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

?

mmap父子進程間通信:

文件inode屬性

struct stat

{

?????? 存儲指針地址;

?????? 大小;

?????? 權限;

?????? 類型;

?????? 所以者;

}

/***
mmap_fork.c
***/
#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()
{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);p = (int*)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(p == MAP_FAILED){perror("mmap error");exit(1);}close(fd);pid = fork();if(0 == pid){*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(-1 == ret){perror("munmap error");exit(1);}}return 0;
}

運行結果:

ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc mmap_fork.c -o mmap_fork

ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./mmap_fork

child, *p = 2000, var = 1000

parent, *p = 2000, var = 100

?

mmap創建匿名映射區

/***
fork_mmap_linux.c
***/
#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()
{int *p;pid_t pid;p = (int*)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED | MAP_ANON,-1,0);if(p == MAP_FAILED){perror("mmap error");exit(1);}pid = fork();if(0 == pid){var = 1000;*p = 2000;printf("child, *p = %d,var = %d\n",*p,var);}else{sleep(1);//    printf("parent,*p = %d\n",*p);printf("child, *p = %d,var = %d\n",*p,var);wait(NULL);int ret = munmap(p,4);if(-1 == ret){perror("munmap error");exit(1);}}return 0;
}

運行結果:

ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc fork_map_linux.c -o fork_map_linux

ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./fork_map_linux

child, *p = 2000,var = 1000

child, *p = 2000,var = 100

?

注意:MAP_ANONYMOUS和MAP_ANON 這兩個宏是linux操作系統特有的宏,再類Unix系統中如無該宏的定義,可以使用以下步驟來完成匿名映射區的建立。

  1. fd = open(“/dev/zero”,O_RDWR);
  2. p = mmap(NULL,size,PROT_READ|PROT_WRITE,MMAP_SHARED,fd,0);
/***
fork_map_anon.c
***/
#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()
{int *p;pid_t pid;int fd = open("/dev/zero",O_RDWR);p = (int*)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(p == MAP_FAILED){perror("mmap error");exit(1);}pid = fork();if(0 == pid){var = 1000;*p = 2000;printf("child, *p = %d,var = %d\n",*p,var);}else{sleep(1);//    printf("parent,*p = %d\n",*p);printf("child, *p = %d,var = %d\n",*p,var);wait(NULL);int ret = munmap(p,4);if(-1 == ret){perror("munmap error");exit(1);}}return 0;
}

運行結果:

buntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc fork_map.c -o fork_map

ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./fork_map

child, *p = 2000,var = 1000

child, *p = 2000,var = 100

?

mmap無血緣關系進程間通信:

/***
mmap_w.c
***/
#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;
};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,0664);ftruncate(fd,sizeof(student));mm = mmap(NULL,sizeof(student),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(mm == MAP_FAILED){sys_err("mmap error");}close(fd);while(1){memcpy(mm,&student,sizeof(student));student.id++;sleep(2);}munmap(mm,sizeof(student));return 0;
}
/***
mmap_r.c
***/
#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;
};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(-1 == fd)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,name = %s,%c\n",mm->id,mm->name,mm->sex);sleep(2);}munmap(mm,sizeof(student));return 0;
}

?

轉載于:https://www.cnblogs.com/wanghao-boke/p/11317614.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384891.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384891.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384891.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux之文件通信

/** 后執行,嘗試讀取另外一個進程寫入文件的內容*/ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <string.h>int main(void) {char buf[1024];char *str "----------test2 write secesuss---…

重載函數和重載運算符

C允許在同一個作用域中的某個函數和運算符指定多個定義&#xff0c;分別稱為函數重載和運算符重載。 重載聲明是指一個與之前已經在該作用域內聲明過的函數或方法具有相同名稱的聲明&#xff0c;但他們的參數列表和定義&#xff08;實現&#xff09;不相同。 當調用一個重載函數…

二元運算符重載

以非成員函數方式重載運算符 /*** overtwo.cpp ***/ #include<iostream> using namespace std;class Box {public:Box(double l 2.0,double b 2.0,double h 2.0){length l;breadth b;height h;}double getVolume(){return length*breadth*height;}private:double l…

一元運算符重載

一元運算符只對一個操作數進行操作&#xff0c;下面是一元運算符實例&#xff1a; 遞增運算符&#xff08;&#xff09; 和遞減運算符&#xff08;--&#xff09;一元減運算符&#xff0c;即符號&#xff08;-&#xff09;邏輯非運算符&#xff08;!&#xff09;/*** overone.c…

關系運算符重載

C語言支持各種關系運算符重載(<,>,>,<,)&#xff0c;他們可用于比較C內置的數據類型。 支持重載任意一個關系運算符&#xff0c;重載后的關系運算符可以用于比較類的對象。 /*** overrealate.cpp ***/ #include<iostream> using namespace std;class Distanc…

kill函數

kill函數/命令產生信號 kill命令產生信號&#xff1a;kill -SIGKILL pid kill函數&#xff1a;給指定進程發送指定信號(不一定殺死) int kill(pid_t pid, int sig); 成功&#xff1a;0&#xff1b;失敗&#xff1a;-1 (ID非法&#xff0c;信號非法&#xff0c;普通用戶殺i…

下標運算符重載

重載該運算符用于增強操作C數組的功能。 /*** subscript.cpp ***/ #include<iostream> using namespace std; const int SIZE 10;class safearay {private:int arr[SIZE];public:safearay(){register int i;for(i 0; i < SIZE ;i){arr[i] i;} }int& operator…

賦值運算符重載

重載賦值運算符&#xff08;&#xff09;&#xff0c;用于創建一個對象&#xff0c;比如拷貝構造函數。 /*** evaluate.cpp ***/ #include<iostream> using namespace std;class Distance {private:int feet;int inches;public:Distance(){feet 0;inches 0;}Distance(i…

運算符小括號重載

函數調用運算符()可以被重用于類的對象。當重載()時&#xff0c;沒有創造一個新的調用函數的方式&#xff0c;相反地&#xff0c;這是創建一個可以傳遞任意數目參數的運算符函數。 /*** bracke.cpp ***/ #include<iostream> using namespace std;class Distance {private…

自增自減運算符重載

遞增運算符&#xff08;&#xff09;和遞減運算符&#xff08;--&#xff09;是C語言中兩個重要的一元運算符。 /*** addMyself.cpp ***/ #include<iostream> using namespace std;class Time {private:int hours;int minutes;public:Time(){hours 0;minutes 0;}Time(i…

輸入輸出運算符重載

C能夠使用流提取運算符>>和流插入運算符<< 來輸入輸出內置數據類型&#xff0c;也可以重載流提取運算符和流插入運算符來操作對象等用戶自定義的數據類型。 我們有時需要把運算符重載函數聲明為類的友元函數&#xff0c;這樣我們就能不用構造對象而直接調用函數。 …

alarm函數

alarm函數 設置定時器(鬧鐘)。在指定seconds后&#xff0c;內核會給當前進程發送14&#xff09;SIGALRM信號。進程收到該信號&#xff0c;默認動作終止。 每個進程都有且只有唯一個定時器。 unsigned int alarm(unsigned int seconds); 返回0或剩余的秒數&#xff0c;無失敗…

信號捕捉

signal函數 注冊一個信號捕捉函數&#xff1a; typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); 該函數由ANSI定義&#xff0c;由于歷史原因在不同版本的Unix和不同版本的Linux中可能有不同的行為。因此應該盡量避免使用它&#x…

打印未決信號集

信號集操作函數 內核通過讀取未決信號集來判斷信號是否應被處理。信號屏蔽字mask可以影響未決信號集。而我們可以在應用程序中自定義set來改變mask。已達到屏蔽指定信號的目的。 信號集設定 sigset_t set; // typedef unsigned long sigset_t; int sigemptyset(sigset_…

sigaction()函數

sigaction函數 修改信號處理動作&#xff08;通常在Linux用其來注冊一個信號的捕捉函數&#xff09; int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); 成功&#xff1a;0&#xff1b;失敗&#xff1a;-1&#xff0c;設置errno 參數&a…

內核實現信號捕捉原理

信號捕捉特性 進程正常運行時&#xff0c;默認PCB中有一個信號屏蔽字&#xff0c;假定為☆&#xff0c;它決定了進程自動屏蔽哪些信號。當注冊了某個信號捕捉函數&#xff0c;捕捉到該信號以后&#xff0c;要調用該函數。而該函數有可能執行很長時間&#xff0c;在這期間所屏蔽…

pause函數

pause函數 調用該函數可以造成進程主動掛起&#xff0c;等待信號喚醒。調用該系統調用的進程將處于阻塞狀態(主動放棄cpu) 直到有信號遞達將其喚醒。 int pause(void); 返回值&#xff1a;-1 并設置errno為EINTR 返回值&#xff1a; ① 如果信號的默認處理動作是終止進程&a…

SIGCHLD函數

SIGCHLD的產生條件 子進程終止時 子進程接收到SIGSTOP信號停止時 子進程處在停止態&#xff0c;接受到SIGCONT后喚醒時 借助SIGCHLD信號回收子進程 子進程結束運行&#xff0c;其父進程會收到SIGCHLD信號。該信號的默認處理動作是忽略。可以捕捉該信號&#xff0c;在捕捉函數中…

成員訪問控制符重載

類成員訪問運算符&#xff08;->&#xff09;可以被重載&#xff0c;但它比較麻煩它被定義用于為一個類賦予“指針”行為。運算符->必須是一個成員函數。如果使用了->運算符&#xff0c;返回類型必須是指針或者是類的對象。 運算符->通常與指針引用運算符 * 結合使…

C++動態內存

C程序中內存分為兩個部分 棧&#xff1a;在函數內部聲明的所有變量都將占用棧內存。 堆&#xff1a;這是程序中未使用的內存&#xff0c;在程序中可用于動態分配內存。 在很多時候&#xff0c;我們無法提前預知需要多少內存來存儲某個變量的特定信息&#xff0c;所需內存的大小…