Linux进程间通信 -- mmap函数的使用

mmap/munmap函数

函数原型

#include <sys/mman.h>

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

函数功能
mmap可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存 地址,对文件的读写可以直接用指针来做而不需要read/write函数。

munmap()用来取消参数start所指的映射内存起始地址,参数length则是欲取消的内存大小。当进程结束或利用exec相关函数来执行其他程序时,映射内存会自动解除,但关闭对应的文件描述符时不会解除映射。

mmap参数说明

  • addr
    mmap函数中如果addr参数为NULL,内核会自己在进程地址空间中选择合适的地址建立映射。如果addr不是NULL,则给内核一个提示,应该从什么地址开始映射,内核会选择addr之上的某个合适的地址开始映射。建立映射后,真正的映射首地址通过返回值可以得到。

  • len
    len参数是需 要映射的那一部分文件的长度。

  • off
    off参数是从文件的什么位置开始映射,必须是页大小的整数倍(在32位体系统结构上通常是4K)。

  • filedes
    filedes是代表该文件的描述符。

  • prot
    prot参数有四种取值:
    PROT_EXEC表示映射的这一段可执行,例如映射共享库
    PROT_READ表示映射的这一段可读
    PROT_WRITE表示映射的这一段可写
    PROT_NONE表示映射的这一段不可访问

  • flag
    flag参数有很多种取值,常用的两种如下,其它取值可查看mmap(2):

    MAP_SHARED多个进程对同一个文件的映射是共享的,一个进程对映射的内存做了修 改,另一个进程也会看到这种变化。

    MAP_PRIVATE多个进程对同一个文件的映射不是共享的,一个进程对映射的内存做了修改,另一个进程并不会看到这种变化,也不会真的写到文件中去。

函数返回值
如果mmap成功则返回映射首地址,如果出错则返回常数MAP_FAILED

当进程终止时,该进程的映射内存会自动解除,也可以调用munmap解除映射。
munmap成功返回0,出错返回-1。

mmap操作修改hello文件:

yu@ubuntu:~/Linux/211$ vi hello
yu@ubuntu:~/Linux/211$ cat hello
hello
yu@ubuntu:~/Linux/211$ od -tx1 -tc hello
0000000  68  65  6c  6c  6f  0a
          h   e   l   l   o  \n
0000006

mmap.c源码:

/*mmap.c*/
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>

int main()
{
    int *p;
    int fd = open("hello", O_RDWR);
    if(fd < 0){
        perror("open hello");
        exit(1);
    }
    /* 将文件映射至进程的地址空间 */
    p = mmap(NULL, 6, PROT_WRITE, MAP_SHARED, fd, 0);
    if(p == MAP_FAILED){
        perror("mmap");
        exit(1);
    }
    /* 映射完后, 关闭文件也可以操纵内存 */ 
    close(fd);
    printf("%c\n", p[0]);
    p[0] = 'A';
    p[1] = '\0';
    printf("%c\n", p[0]);
    munmap(p, 6);

    return 0;
}

编译及执行测试:

yu@ubuntu:~/Linux/211$ vi hello
yu@ubuntu:~/Linux/211$ cat hello
hello
yu@ubuntu:~/Linux/211$ gcc mmap.c
yu@ubuntu:~/Linux/211$ ./a.out
h
A
yu@ubuntu:~/Linux/211$ cat hello
A
yu@ubuntu:~/Linux/211$ od -tx1 -tc hello
0000000  41  00  00  00  00  00  0a
          A  \0  \0  \0  \0  \0  \n
0000007

如上所示,成功修改了hello文件。

注意事项:
* 用于进程间通信时,一般设计成结构体,来传输通信的数据
* 进程间通信的文件,应该设计成临时文件
* 当报总线错误时,优先查看共享文件是否有存储空间

具体通信案例请见(Linux进程共享通信 – mmap实现):
http://blog.csdn.net/y396397735/article/details/50651633

你可能感兴趣的:(linux,mmap)