进程间通信之内存映射区笔记
【摘要】 进程间通信使用内存映射区mmap相关知识笔记!
- 进程间通信
-
- 有血缘关系的
- 父子进程共享内存映射区
- 没有血缘关系的进程间通信
- 如何通信?
- 有血缘关系的
- Mmap 实现内存映射:
- 必须有一个文件
- 文件数据什么时候有用:
- 单纯文件映射
- 进程间通信:
- 文件数据是没有用的
- Mmap - 创建内存映射
- 作用:将磁盘文件的数据映射到内存,用户通过修改内存就能修改磁盘文件
- 函数原型:
void *mmap(
void *addr, //映射区首地址,传NULL
size_t length, //映射区的大小
- 100byte - 4k
- 不能为0
- 一般文件多大,length就指定多大
int prot, //映射区的权限
- PROT_READ -- 映射区必须要有读权限
- PROT_WRITE
- PROT_READ | PROT_WRITE
int flags,//标志位参数
- MAP_SHARED
- 修改了内存数据会同步到磁盘
- MAP_PRIVATE
- 修改了内存数据不会同步到磁盘
int fd, //文件描述符
- 干嘛的文件描述符?
- 要映射的文件对应fd
- 要么得到?
- Open()
off_t offset//映射文件的偏移量
- 映射的时候文件指针的偏移量
- 必须是4k的整数倍
- 0
);
- 返回值:
- 映射区的首地址 - 调用成功
- 调用失败:MAP_FAILED
- Munmap - 释放内存映射区
- 函数原型:
int munmap(void *addr, size_t length);
- Addr -- mmap 的返回值,映射区的首地址
- Length -- mmap的第二个参数,映射区的长度
-
思考问题:
- 如果对mmap的返回值(ptr) 做++操作(ptr++),munmap是否能够成功?
- 不能
- Char *pt = ptr;
- 如果open是O_RDONLY,mmap时port参数指定PROT_READ | PROT_WRITE会怎样?
- mmap调用失败
- open文件指定的权限应该大于等于mmap第三个参数prot指定的权限
- 如果文件偏移量为1000会怎样?
- 必须是4096的整数倍
- 如果不检测mmap的返回值会怎样?
- Mmap 什么情况下会调用失败?
- 第二个参数length = 0
- 第三个参数必须指定PROT_READ
- Fd 对应的打开权限必须大于等于prot权限
- 偏移量:必须是4096的整数倍
- 可以open的时候O_CREAT一个新文件来创建映射区吗?
- 可以,需要做文件拓展
- Lseek
- Truncate(fd, length)
- mmap后关闭文件描述符,对mmap映射有没有影响?
- 没有影响
- 对ptr越界操作会怎样?
- 段错误
-
进程间通信
- 有血缘关系的
- 父子进程共享内存映射区
- 没有血缘关系的进程间通信
- 如何通信?
- 不能使用匿名映射的方式
- 只能借助磁盘文件创建映射区 -- temp
- 不阻塞
- a进程(a.c) b进程(b.c)
- A.c
- Int fd = open("temp");
- Void *ptr = mmap(,,,fd,0);
- 对映射区进行读写操作
- B.c
- Int fd1 = open("temp");
- Void *ptr1 = mmap(,,,,fd, 0);
- 对映射区做读写操作
-
mmap实现内存映射:
- 必须有一个文件
- 文件数据什么时候有用:
- 单纯文件映射
- 进程间通信:
- 文件数据是没有用的
-
父子进程永远共享的东西?
- 文件描述符
- 内存映射区
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
int main(int argc, char argv[])
{
int fd, len, ret;
void *ptr;
// 1、打开一个文件
fd = open("temp.txt", O_RDWR);
// 计算文件的大小
len = lseek(fd, 0, SEEK_END);
// 2、创建内存映射区
ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
{
perror("mmap error\n");
exit(1);
}
printf("%s", (char *)ptr);
// 3、释放内存映射区
ret = munmap(ptr, len);
if (ret == -1)
{
perror("munmap error\n");
exit(1);
}
return 0;
}
如果对mmap的返回值(ptr) 做++操作(ptr++),munmap是否能够成功?
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
int main(int argc, char argv[])
{
int fd, len, ret;
void *ptr;
// 1、打开一个文件
fd = open("temp.txt", O_RDWR);
// 计算文件的大小
len = lseek(fd, 0, SEEK_END);
// 2、创建内存映射区
ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
{
perror("mmap error\n");
exit(1);
}
printf("%s", (char *)ptr);
ptr++;
// 3、释放内存映射区
ret = munmap(ptr, len);
if (ret == -1)
{
perror("munmap error\n");
exit(1);
}
return 0;
}
如果open是O_RDONLY,mmap时port参数指定PROT_READ | PROT_WRITE会怎样?
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
int main(int argc, char argv[])
{
int fd, len, ret;
char *pt;
void *ptr;
// 1、打开一个文件
fd = open("temp.txt", O_RDONLY);
// 计算文件的大小
len = lseek(fd, 0, SEEK_END);
// 2、创建内存映射区
ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
{
perror("mmap error\n");
exit(1);
}
printf("%s", (char *)ptr);
// ptr++;
pt = ptr;
pt++;
// 3、释放内存映射区
ret = munmap(ptr, len);
if (ret == -1)
{
perror("munmap error\n");
exit(1);
}
return 0;
}
如果文件偏移量为1000会怎样?
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
int main(int argc, char argv[])
{
int fd, len, ret;
char *pt;
void *ptr;
// 1、打开一个文件
fd = open("temp.txt", O_RDWR);
// 计算文件的大小
len = lseek(fd, 0, SEEK_END);
// 2、创建内存映射区
ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 1000);
if (ptr == MAP_FAILED)
{
perror("mmap error\n");
exit(1);
}
printf("%s", (char *)ptr);
// ptr++;
pt = ptr;
pt++;
// 3、释放内存映射区
ret = munmap(ptr, len);
if (ret == -1)
{
perror("munmap error\n");
exit(1);
}
return 0;
}
mmap后关闭文件描述符,对mmap映射有没有影响?
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
int main(int argc, char argv[])
{
int fd, len, ret;
char *pt;
void *ptr;
// 1、打开一个文件
fd = open("temp.txt", O_RDWR);
// 计算文件的大小
len = lseek(fd, 0, SEEK_END);
// 2、创建内存映射区
ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
{
perror("mmap error\n");
exit(1);
}
close(fd);
printf("%s", (char *)ptr);
// ptr++;
pt = ptr;
pt++;
// 3、释放内存映射区
ret = munmap(ptr, len);
if (ret == -1)
{
perror("munmap error\n");
exit(1);
}
return 0;
}
父子进程间通信mmap
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char argv[])
{
int fd, len, ret;
pid_t pid;
char *pt;
void *ptr;
// 1、打开一个文件
fd = open("temp.txt", O_RDWR);
// 计算文件的大小
len = lseek(fd, 0, SEEK_END);
// 2、创建内存映射区
ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
{
perror("mmap error\n");
exit(1);
}
// 创建子进程
pid = fork();
if (pid == -1)
{
perror("fork error");
exit(1);
}
if (pid > 0)
{
/* 父进程写数据 */
strcpy((char *)ptr, "爱你美丽,想你美丽!\n");
// 回收子进程
wait(NULL);
}
if (pid == 0)
{
/* 子进程读数据 */
sleep(1);
printf("%s", (char *)ptr);
}
/* printf("%s", (char *)ptr);
// ptr++;
pt = ptr;
pt++; */
// 3、释放内存映射区
ret = munmap(ptr, len);
if (ret == -1)
{
perror("munmap error\n");
exit(1);
}
close(fd);
return 0;
想使有血缘关系之间的进程进行通信,可以使用匿名内存映射的方式进行通信。
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char argv[])
{
int len = 4096;
int ret;
pid_t pid;
char *pt;
void *ptr;
// 2、创建内存映射区
ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (ptr == MAP_FAILED)
{
perror("mmap error\n");
exit(1);
}
// 创建子进程
pid = fork();
if (pid == -1)
{
perror("fork error");
exit(1);
}
if (pid > 0)
{
/* 父进程写数据 */
strcpy((char *)ptr, "爱你美丽,想你美丽!\n");
// 回收子进程
wait(NULL);
}
if (pid == 0)
{
/* 子进程读数据 */
sleep(1);
printf("%s", (char *)ptr);
}
// 3、释放内存映射区
ret = munmap(ptr, len);
if (ret == -1)
{
perror("munmap error\n");
exit(1);
}
return 0;
}
内存映射使用在没有血缘关系的两个进程间的通信
write.c
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char argv[])
{
int fd, len;
int ret;
pid_t pid;
char *pt;
void *ptr;
// 打开文件
fd = open("temp.txt", O_RDWR | O_CREAT, 0664);
ftruncate(fd, 4096);
len = lseek(fd, 0, SEEK_END);
// 2、创建内存映射区
ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
{
perror("mmap error\n");
exit(1);
}
// 操作共享内存映射区写数据
while (1)
{
char *p = (char *)ptr;
p += 1024;
strcpy(p, "meili i love you ,you go to where?\n");
sleep(2);
}
// 3、释放内存映射区
ret = munmap(ptr, len);
if (ret == -1)
{
perror("munmap error\n");
exit(1);
}
close(fd);
return 0;
}
read.c
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char argv[])
{
int fd, len;
int ret;
pid_t pid;
char *pt;
void *ptr;
// 1、打开文件
fd = open("temp.txt", O_RDWR | O_CREAT, 0664);
ftruncate(fd, 4096);
len = lseek(fd, 0, SEEK_END);
// 2、创建内存映射区
ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
{
perror("mmap error\n");
exit(1);
}
// 操作内存处理数据
while (1)
{
sleep(1);
printf("%s", (char *)ptr + 1024);
}
// 3、释放内存映射区
ret = munmap(ptr, len);
if (ret == -1)
{
perror("munmap error\n");
exit(1);
}
close(fd);
return 0;
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)