进程间通信之存储映射区mmap
存储映射区mmap()
存储映射区就是将一个磁盘文件映射到内存,通过操作内存,然后可以选择是否影响磁盘文件,从而修改磁盘文件。
c
#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返回值
成功则返回系统分配的内存地址
失败则返回MAP_FAILED
munmap返回值
成功则返回0
失败则返回-1
参数
addr: 自己指定地址,或者设置为NULL,让系统分配。
length: 打开文件的文件长度,使用lseek获取长度。
prot: 映射区读写权限
读:PROT_READ 写:PROT_WRITE 执行:PROT_EXEC
flags: 映射区的特性。
MAP_SHARED: 写入映射区的数据会写回文件, 且允许其他映射该文件的进程共享。
MAP_PRIVATE: 对此区域所做的修改不会写回原文件。
fd: 打开文件的文件描述符
offset: 打开文件的偏移量,通常设置为0,即不偏移
示例:
父子进程使用mmap进行通信
c
//mmap.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
// void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
// int munmap(void *addr, size_t length);
int fd = open("./test", O_RDWR);
if (fd < 0)
{
perror("open error");
return -1;
}
int len = lseek(fd, 0, SEEK_END);
void *addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
memset(addr, 0x00, strlen(addr));
close(fd);
if (MAP_FAILED == addr)
{
perror("mmap error");
return -1;
}
int ret = fork();
if (ret > 0)
{
// father
memcpy(addr, "hello world", strlen("hello world"));
wait(NULL);
ret = munmap(addr, len);
if (ret < 0)
{
perror("munmap error");
return -1;
}
else
{
printf("mmap released\n");
}
}
else if (ret == 0)
{
// child
sleep(1);
char *p = (char *)addr;
printf("str is [%s]\n", p);
}
else
{
perror("fork error");
return -1;
}
return 0;
}
//输出
str is [hello world]
mmap released
匿名映射区
添加匿名标志MAP_ANONYMOUS,并手动设置映射区大小
c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
// void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
// int munmap(void *addr, size_t length);
// int fd = open("./test", O_RDWR);
// if (fd < 0)
// {
// perror("open error");
// return -1;
// }
// int len = lseek(fd, 0, SEEK_END);
int len =4096;
void *addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
memset(addr, 0x00, strlen(addr));
//close(fd);
if (MAP_FAILED == addr)
{
perror("mmap error");
return -1;
}
int ret = fork();
if (ret > 0)
{
// father
memcpy(addr, "hello world", strlen("hello world"));
wait(NULL);
ret = munmap(addr, len);
if (ret < 0)
{
perror("munmap error");
return -1;
}
else
{
printf("mmap released\n");
}
}
else if (ret == 0)
{
// child
sleep(1);
char *p = (char *)addr;
printf("str is [%s]\n", p);
}
else
{
perror("fork error");
return -1;
}
return 0;
}
//输出
str is [hello world]
mmap released