进程间通信:内存映射

进程间通信:内存映射

在这里插入图片描述

在这里插入图片描述

父子进程间

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

description:
    mmap() creates a new mapping in the virtual address space of the calling process.  The starting address 
    for the new mapping is specified in addr.The length argument specifies the length of the mapping (which 
    must be greater than 0).
参数:
    -addr:      NULL, 内存映射的首地址,NULL由系统指定,也是返回值
    -length:    映射数据长度,不能为0,一般为sizeof(file),如果没达到页的大小,那么会自动达到页的大小
                获取文件长度:stat(); lseek();
    -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.
                    note:   PROTREAD | PROTWRITE
                            要操作映射区必须有读权限

    -flags:      MAP_SHARED:     映射区的数据会自动和磁盘文件同步,进程间通信必须要设置这个选项
                MAP_PRIVATE:   不同步,内存映射区的数据改变了不会修改源文件,会重新创建一个新的文件(copy on write)
                ......
    -fd:        需要操作映射文件的文件描述符
                note:
                    -通过open获取,open打开的是磁盘文件
                    -文件的大小不能为0,权限不能和port的权限冲突
                        eg:
                            open                port
                            RDONLY(RDWR)        PORT_READ
                            RDWR                PORTREAD|PORTWROTE 
    -offset:    偏移量:0不偏移,必须为4K的整数倍,一般不用

返回值:
    -成功:返回映射的首地址
    -失败:返回一个宏(MAP_FAILED: (void *)-1 )


int munmap(void *addr, size_t length);
    -功能:释放内存映射
    -参数:
    -addr:      要释放内存映射的首地址,即使创建的返回值
    -length:    和创建时的值相同
*/

/*
使用内存映射实现进程间通信:
    1.有关系的进程(父子进程)
        -还没有子进程的时候
            -通过唯一的父进程,先创建内存映射区
        -有了内存映射区以后,创建子进程
        -父子进程共享创建的内存映射区
I
    2.没有关系的进程间通信
        -准备一个大小不是0的磁盘文件
        -进程1通过磁盘文件创建内存映射区
            -得到一个操作这块内存的指针
        -进程2通过磁盘文件创建内存映射区
            -得到一个操作这块内存的指针
        -使用内存映射区通信
    注意:
        内存映射区的通信默认非阻塞
*/


#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <wait.h>

int main(){

    int fd = open("a.txt", O_RDWR);
    if(fd == -1){
        perror("open");
        return -1;
    }
    //获取文件大小
    int size = lseek(fd, 0, SEEK_END);

    //创建内存映射区
    void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    //创建的位置 大小 权限 是否同步到内存 映射文件 偏移量0(从头开始)

    if(ptr == MAP_FAILED){
        perror("mmap");
        return -1;
    }

    //fork子进程
    pid_t pid = fork();

    if(pid > 0){
        //parent
        strcpy((char *)ptr, "come on, my child...");

    }else if(pid == 0){
        //child
        wait(NULL);
        char buf[64];
        strcpy(buf, (char *)ptr);
        printf("child read data : %s \n", buf);

    }else if(pid < 0){
        perror("pid");
        return -1;
    }

    //关闭内存映射区
    munmap(ptr, size);
    close(fd);
    
    return 0;
}

两个非亲缘进程间

process1

/*
 2.没有关系的进程间通信
        -准备一个大小不是0的磁盘文件
        -进程1通过磁盘文件创建内存映射区
            -得到一个操作这块内存的指针
        -进程2通过磁盘文件创建内存映射区
            -得到一个操作这块内存的指针
        -使用内存映射区通信

*/

#include <stdio.h>
#include <sys/mman.h>
#include <string.h>

//open
#include <fcntl.h>
#include <sys/stat.h> 
//#include <sys/types.h>

//lseek
#include <sys/types.h>
#include <unistd.h>

int main(){

    int fd = open("a.txt", O_RDWR);

    int size = lseek(fd, 0, SEEK_END);

    void *ptr = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
                    //位置 大小 权限 是否同步 文件 偏移量

    strcpy((char *)ptr, "hello, this is process 1......");

    munmap(ptr, size);

    return 0;
}

process2

#include <stdio.h>
#include <sys/mman.h>
#include <string.h>

//open
#include <fcntl.h>
#include <sys/stat.h> 
//#include <sys/types.h>

//lseek
#include <sys/types.h>
#include <unistd.h>

//wait()
#include <wait.h>

int main(){

    int fd = open("a.txt", O_RDWR);

    int size = lseek(fd, 0, SEEK_END);

    void *ptr = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
                    //位置 大小 权限 是否同步 文件 偏移量

    wait(NULL);
    char buf[64];
    strcpy(buf, (char *)ptr);
    printf("process 2: %s \n", buf);

    munmap(ptr, size);

    return 0;
}

在这里插入图片描述

1.如果对mmap的返回值(ptr)++操作(ptr++), munmap是否能够成功?
	void * ptr = mmap( .. .);
	ptr++;可以对其进行++操作
	munmap(ptr, len);1/错误,要保存地址
	
2.如果open时o_RDONrY, mmap时prot参数指定PROT_READ|PROT_WRITE会怎样?
	错误,返回MAP_FAILED
	open()函数中的权限建议和prot参数的权限保持一致。
	
3 如果文件偏移量为1000会怎样?
	偏移量必须为4K的整数倍,返回MAP_FAILED
	
4 mmap什么情况下会调用失败?
	-第二个参数: length = 0
	-第三个参数: port
				-只指定了写权限
				-port 权限和 open权限不一致
	

5 可以open的时候O_CREAT一个新文件来创建映射区吗?
	- 可以, 创建文件的大小不能为0
	- 可以对新的文件进行拓展
		- lseek()
		- truncate()

6 mmap后关闭文件描述符,对mmap映射有没有影响?
	-不会,映射区还是存在,创建映射区的fd被关闭了没有影响(创建时对fd进行了拷贝)
	
7 对ptr越界操作会怎样?
	-越界操作操作的的非法内存,产生段错误。

内存映射做内存拷贝

#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(){

    int fd = open("a.txt", O_RDWR);
    if(fd == -1){
        perror("open");
        return -1;
    }
    //获取文件的大小
    int size = lseek(fd, 0, SEEK_END);

    int fdnew = open("copy.txt", O_CREAT|O_RDWR, 0664);
    if(fdnew == -1){
        perror("open new");
        return -1;
    }

    //对新创建的文件拓展
    truncate("copy.txt", size);
    write(fdnew, " ", 1);

    //分别做内存映射
    void *ptr = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
    void *ptrnew = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_SHARED, fdnew, 0);

    if(ptr == MAP_FAILED || ptrnew == MAP_FAILED){
        perror("mmap");
        return -1;
    }

    //内存拷贝
    char buf[1024];
    // strcpy(buf, (char *)ptr);
    // strcpy((char *)ptrnew, buf);

    memcpy(ptrnew, ptr, size);

    munmap(ptrnew, size);
    munmap(ptr, size);
    
    close(fdnew);
    close(fd);

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值