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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

linux 进程通信之 mmap

發(fā)布時(shí)間:2024/1/23 linux 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 进程通信之 mmap 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一,管道PIPE

二,FIFO通信

三,mmap通信

創(chuàng)建內(nèi)存映射區(qū)。

#include <sys/mman.h> void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); int mmap(void *addr, size_t length);

函數(shù)mmap:打開(kāi)一個(gè)文件,指定一個(gè)文件的區(qū)域,作為一個(gè)區(qū)域,映射到內(nèi)存中,以后就直接操作那個(gè)內(nèi)存,就能夠?qū)崿F(xiàn)進(jìn)程間的通信。因?yàn)槭莾?nèi)存操作,所以速度最快。

  • addr:固定NULL
  • length: 拿出文件中的多長(zhǎng)的一段,映射到內(nèi)存。
  • offset: 從文件內(nèi)容中的哪個(gè)位置開(kāi)始拿。
  • prot

PROT_EXEC Pages may be executed

PROT_READ Pages may be read.

PROT_WRITE Pages may be written

PROT_NONE Pages may not be accessed

  • flags

MAP_SHARED: 對(duì)內(nèi)存里的值進(jìn)行修改,會(huì)反映到文件,也就是文件也被修改。

MAP_PRIVATE:對(duì)內(nèi)存里的值進(jìn)行修改,不會(huì)反映到文件,文件不會(huì)被修改。

  • offset: 起始位置
  • 返回值:

成功:可用的內(nèi)存的首地址

失敗:MAP_FAILED(that is, (void *) -1)

釋放內(nèi)存映射區(qū).

#include <sys/mman.h> int munmap(void *addr, size_t length);
  • addr: mmap的返回值;
  • length: mmap創(chuàng)建的長(zhǎng)度;
  • 返回值: 成功0, 失敗-1.

例子:

#include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h>int main() {int fd = open("mem", O_RDWR);// char *buf = mmap(NULL, 8, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);char *buf = mmap(NULL, 8, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);printf("%s\n", buf);strcpy(buf, "FFFFF");//釋放映射區(qū)munmap(buf, 8);close(fd); }

mmap的七個(gè)問(wèn)題:

  • 如果更改上面例子里變量buf的地址,釋放的時(shí)候munmap,還能成功嗎?

不能成功,錯(cuò)誤信息: [Invalid argument]

  • 對(duì)映射區(qū)的操作,越界了怎么樣?

open文件size > 要寫入的size > mmap參數(shù)的length: 能夠全部寫入文件。

open文件size < 要寫入的size > mmap參數(shù)的length: 不能全部寫入文件,能夠給寫入的size是open文件的size

  • 偏移量隨便填個(gè)數(shù)字會(huì)怎么樣?

mmap函數(shù)出錯(cuò),錯(cuò)誤信息: [Invalid argument]

offset必須是4K的整數(shù)倍,[0, 4*1024......]

用[stat]命令查看文件,發(fā)現(xiàn)文件的size實(shí)際小于4096,但是[IO Block: 4096]

File: pi2.c

Size: 442 Blocks: 8 IO Block: 4096 regular file

Device: 801h/2049d Inode: 424247 Links: 1

Access: (0664/-rw-rw-r--) Uid: ( 1000/ ys) Gid: ( 1000/ ys)

Access: 2019-05-02 12:54:13.812282158 +0800

Modify: 2019-04-29 13:49:42.489004001 +0800

Change: 2019-04-29 13:49:42.489004001 +0800

  • 如果文件描述符先關(guān)閉,對(duì)mmap映射有沒(méi)有影響。

沒(méi)有影響。

  • open的時(shí)候,可以用新創(chuàng)建一個(gè)文件的方式,來(lái)創(chuàng)建映射區(qū)嗎?

錯(cuò)誤:Bus error(core dumped).

錯(cuò)誤理由是:創(chuàng)建的文件的size為0,所以出上面的錯(cuò)誤。新創(chuàng)建一個(gè)文件后,馬上把文件大小擴(kuò)展一下就不會(huì)發(fā)生錯(cuò)誤了。

int fd = open("mem", O_RDWR|O_CREAT, 0666); ftruncate(fd, 8); //把新創(chuàng)建的文件mem的大小擴(kuò)展為8.
  • open文件時(shí),選擇O_WRONLY,可以嗎

mmap函數(shù)出錯(cuò),錯(cuò)誤: [Permission denied]。

因?yàn)橐盐募膬?nèi)容讀到內(nèi)存,所以隱含一次讀取操作,所有沒(méi)有讀的權(quán)限的話,就出這個(gè)錯(cuò)誤。

  • 當(dāng)選擇MAP_SHARED的時(shí)候,open文件選擇O_RDONLY,prot可以選擇[PROT_READ|PROT_WRITE]嗎

mmap函數(shù)出錯(cuò),錯(cuò)誤: 【Permission denied】.

MAP_SHARED的時(shí)候會(huì)去寫文件,但是open的時(shí)候只有讀權(quán)限,所以權(quán)限不夠。

用mmap實(shí)現(xiàn)父子進(jìn)程間通信的例子:

注意:參數(shù)flags必須是MAP_SHARED,因?yàn)?個(gè)進(jìn)程間通信,需要互相讀寫,所以必須是MAP_SHARED

#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/wait.h>int main() {int fd = open("mem", O_RDWR);int* mem = mmap(NULL, 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (mem == MAP_FAILED) {perror("mmap");return -1;}pid_t pid = fork();if (pid == 0) {*mem = 100;printf("child:mem=%d\n", *mem);sleep(3);printf("child:mem=%d\n", *mem);}else if (pid > 0) {sleep(1);printf("parent:mem=%d\n", *mem);*mem = 200;printf("parent:mem=%d\n", *mem);wait(NULL);}munmap(mem, 4);close(fd); }

執(zhí)行結(jié)果:

child:mem=100

parent:mem=100

parent:mem=200

child:mem=200

不知道讀者同學(xué)們發(fā)現(xiàn)了沒(méi)有,用mmap有個(gè)非常雞肋的地方,就是必須要使用一個(gè)文件,其實(shí)這個(gè)文件對(duì)程序沒(méi)有什么作用。所以linux給我們提供了一個(gè)方法,叫做[匿名映射]。

匿名映射:在調(diào)用mmap函數(shù)時(shí)候,在flags參數(shù)那里,設(shè)置[MAP_ANON],并在fd參數(shù)那里設(shè)置[-1]。

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

有個(gè)問(wèn)題,在有些unix系統(tǒng)里是沒(méi)有[MAP_ANON][MAP_ANONYMOUS]這2個(gè)宏的,這2個(gè)宏的作用是一樣的,其中一個(gè)是簡(jiǎn)寫。那怎么辦呢?

使用下面2個(gè)文件去映射,因?yàn)橐梦募?#xff0c;所以必須還得有open的調(diào)用,但好處是不用事先做出一個(gè)大小合適的文件了。

  • /dev/zero: 可以隨意映射,size無(wú)限大,諢名為[聚寶盆]
  • /dev/null:可以隨意映射,size無(wú)限大,但映射完后,文件里不會(huì)存有任何內(nèi)容,所以也叫[無(wú)底洞],一般錯(cuò)誤日志太多,而且不想保留的時(shí)候,會(huì)重定向到這個(gè)文件。

匿名映射的弱點(diǎn):不能實(shí)現(xiàn)無(wú)血緣關(guān)系進(jìn)程間的通信。

用mmap實(shí)現(xiàn)無(wú)血緣關(guān)系的進(jìn)程間通信的例子:

寫入端:

#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/wait.h>typedef struct _student {int id;char name[20]; } Student;int main(int argc, char *argv[]) {int fd = open("aaa", O_RDWR|O_TRUNC|O_CREAT, 0666);int length = sizeof(Student);ftruncate(fd, length);Student *std = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (std == MAP_FAILED) {perror("mmap");return -1;}int num = 0;while (1) {std->id = num;sprintf(std->name, "xiaoming-%03d", num++);sleep(1);}munmap(std, length);close(fd); }

讀入端:

#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/wait.h>typedef struct _student{int fd;char name[20]; } Student;int main(int argc, char *argv[]) {int fd = open("aaa", O_RDWR);int length = sizeof(Student);Student *std = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (std == MAP_FAILED) {perror("mmap");return -1;}while (1) {printf("id:%03d, name:%s\n", std->id, std->name);sleep(1);}munmap(std, length);close(fd); }

利用mmap實(shí)現(xiàn)用多個(gè)進(jìn)程拷貝一個(gè)文件的例子

核心思想:把要拷貝的文件和目標(biāo)文件都映射成內(nèi)存映射區(qū),然后在各自的子進(jìn)程里做拷貝,拷貝時(shí),注意起點(diǎn)和大小。

#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/wait.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <sys/mman.h>//argv[1]: 進(jìn)程的數(shù)量 //argv[2]: 要拷貝的文件 int main(int argc, char *argv[]) {if (argc < 3) {printf("bad argv, need 3 arg\n");return -1;}//用stat函數(shù)取得文件的大小struct stat sbuf;int ret = stat(argv[2], &sbuf);if (ret < 0) {perror("stat");return -1;}//文件的大小off_t sz = sbuf.st_size;//余數(shù)off_t yu = sz % atoi(argv[1]);//每個(gè)進(jìn)程拷貝的大小off_t proSz = (sz - yu) / atoi(argv[1]);//open src fileint srcfd = open(argv[2], O_RDONLY);//create target filechar wk[20] = {0};sprintf(wk, "%s.copy", argv[2]);int decfd = open(wk, O_RDWR|O_CREAT|O_TRUNC, 0766);//創(chuàng)建和src文件同等大小的目標(biāo)文件ret = ftruncate(decfd, sz);if (ret < 0) {perror("ftruncate");return -1;}//打開(kāi)要被拷貝文件的內(nèi)存映射區(qū)void *dst = mmap(NULL, sz, PROT_READ, MAP_SHARED, srcfd, 0);if (src == MAP_FAILED) {perror("mmap src:");return -1;}//打開(kāi)要目標(biāo)文件的內(nèi)存映射區(qū)void *dst = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_SHARED, decfd, 0);if (dst == MAP_FAILED) {perror("mmap dst:");return -1;}int i;int pCnt = atoi(argv[1]);//創(chuàng)建子進(jìn)程,都是這些子進(jìn)程都是本程序的子進(jìn)程for (i=0; i<pCnt; ++i) {//in child processif (fork() == 0) {break;}}//子進(jìn)程的處理if (i < pCnt) {//last timeif (i == pCnt - 1) {memcpy(dst+i*proSz, src+i*proSz, proSz+yu);}else {memcpy(dst+i*proSz, src+i*proSz, proSz);}}//父進(jìn)程的處理else {for (int i=0; i<pCnt; ++i) {wait(NULL);}//printf("parent pid=%d\n", getpid());if (munmap(src, sz) == -1) {perror(munmap src");}if (munmap(dst, sz) == -1) {perror("munmap dsc");}close(srcfd);close(decfd);}}

?

總結(jié)

以上是生活随笔為你收集整理的linux 进程通信之 mmap的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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