mmap linux 例子,linux 进程通信之 mmap

三,mmap通信

创建内存映射区。

#include

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

int munmap(void *addr, size_t length);

函数mmap:打开一个文件,指定一个文件的区域,作为一个区域,映射到内存中,以后就直接操作那个内存,就能够实现进程间的通信。因为是内存操作,所以速度最快。

addr:固定NULL

length:拿出文件中的多长的一段,映射到内存。

offset:从文件内容中的哪个位置开始拿。

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:对内存里的值进行修改,会反映到文件,也就是文件也被修改。

MAP_PRIVATE:对内存里的值进行修改,不会反映到文件,文件不会被修改。

offset:起始位置

返回值

成功:可用的内存的首地址

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

释放内存映射区。

#include

int munmap(void *addr, size_t length);

addr:mmap的返回值

length:mmap创建的长度

返回值:成功0;失败-1.

例子:

#include

#include

#include

#include

#include

#include

#include

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");

//释放映射区

munmap(buf, 8);

close(fd);

}

mmap的七个问题:

如果更改上面例子里变量buf的地址,释放的时候munmap,还能成功吗?

不能成功。错误信息:【Invalid argument】

对映射区的操作,越界了会怎么样。

open文件size > 要写入的size > mmap参数的length:能够全部写入文件。

open文件size < 要写入的size > mmap参数的length:不能全部写入文件,能够写入的size是open文件的size

偏移量随便填个数字会怎么样。

mmap函数出错,错误信息:【Invalid argument】

offset必须是4K的整数倍,【0,4*1024。。。】

用【stat】命令查看文件,发现文件的size实际小于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

如果文件描述符先关闭,对mmap映射有没有影响。

没有影响。

open的时候,可以用新创建一个文件的方式,来创建映射区吗?

错误:Bus error (core dumped)。

错误理由是:创建的文件的size为0,所以出上面的错误。新创建一个文件后,马上把文件大小扩展一下就不会发生错误了。

int fd = open("mem", O_RDWR|O_CREAT, 0666);

ftruncate(fd, 8);//把新创建的文件mem的大小扩展为8.

open文件时,选择O_WRONLY,可以吗

mmap函数出错,错误:【Permission denied】。

因为要把文件的内容读到内存,所以隐含一次读取操作,所以没有读的权限的话,就出这个错误。

当选择MAP_SHARED的时候,open文件选择O_RDONLY,prot可以选择【PROT_READ|PROT_WRITE】吗

mmap函数出错,错误:【Permission denied】。

MAP_SHARED的时候会去写文件,但是open的时候只有读权限,所以权限不够。

用mmap实现父子进程间通信的例子:

注意:参数flags必须是MAP_SHARED,因为2个进程间通信,需要互相读写,所以必须是MAP_SHARED

#include

#include

#include

#include

#include

#include

#include

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);

}

执行结果:

child:mem=100

parent:mem=100

parent:mem=200

child:mem=200

不知道读者同学们发现了没有,用mmap有个非常鸡肋的地方,就是必须要使用一个文件,其实这个文件对程序没有什么作业。所以linux给我们提供了一个方法,叫做【匿名映射】。

匿名映射:在调用mmap函数时候,在flags参数那里,设置【MAP_ANON】,并在fd参数那里设置【-1】。

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

有个问题,在有些unix系统里是没有【MAP_ANON】【MAP_ANONYMOUS】这2个宏的,这2个宏的作用是一样的,其中一个是简写。那怎么办呢?

使用下面2个文件去映射,因为要用文件,所以必须还得有open的调用,但好处是不用事先做出一个大小合适的文件了。

/dev/zero:可以随意映射,size无限大,诨名叫【聚宝盆】

/dev/null:可以随意映射,size无限大,但映射完后,文件里不会存有任何内容,所以也被叫成【无底洞】,一般错误日志太多,而且不想保留的时候,会重定向到这个文件。

匿名映射的弱点:不能实现无学员关系进程间的通信。

用mmap实现无血缘关系的进程间通信的例子:

写入端:

#include

#include

#include

#include

#include

#include

#include

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

#include

#include

#include

#include

#include

#include

typedef struct _student{

int id;

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实现用多个进程拷贝一个文件的例子(代码还没写完)

#include

#include

#include

#include

#include

#include

#include

#include

#include

//argv[1]:process count

//argv[2]:src file

int main(int argc, char* argv[]){

if(argc < 3){

printf("bad argv,need 3 arg");

return -1;

}

struct stat sbuf;

int ret = stat(argv[2], &sbuf);

if(ret < 0){

perror("stat");

return -1;

}

off_t sz = sbuf.st_size;

off_t yu = sz % atoi(argv[1]);

off_t proSz = (sz - yu) / atoi(argv[1]);

printf("proSz:%ld, yu:%ld\n", proSz, yu);

//open src file

int srcfd = open(argv[2], O_RDONLY);

//create target file

char wk[20] = {0};

sprintf(wk, "%s.copy", argv[2]);

int decfd = open(wk,O_RDWR|O_CREAT|O_TRUNC, 0666);

ret = ftruncate(decfd, sz);

if(ret < 0){

perror("ftruncate");

return -1;

}

void* vc[atoi(argv[1])];

for(int i = 0; i < atoi(argv[1]); ++i){

vc[i] = mmap(NULL, proSz, PROT_READ|PROT_WRITE, MAP_SHARED, decfd, 0);

if(vc[i] == MAP_FAILED){

perror("mmap die:");

return -1;

}

}

close(srcfd);

close(decfd);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值