IPC之共享内存(通过mmap实现)
管道那里只是说了下匿名管道且是用于有血缘关系的进程里面才行,为什么没有提到有名管道,个人认为有名管道没有共享内存用的广泛就没有多说,这里主要给说一说常用的一种用于非血缘关系进程间通信的方法——共享内存。
概念还是概念,学习一个新的东西肯定是从概念进行入手的,那么看看共享内存的概念是什么:
共享内存就是允许两个不相关的进程访问同一个逻辑内存。共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常安排为同一段物理内存。
这次我主要通过mmap函数通过映射同一个普通文件来实现共享内存。普通文件被映射到地址空间后,进程可以向访问普通内存一样对文件进行访问。可以当一个malloc出来的空间进行使用,直接使用memcpy而不用read,write了。
在使用mmap的时候需要注意的就是这个函数的参数。一起看看这个函数。
这么多的参数在图中都有用法解说,下面来说一说每一个参数的注意点:
1.length一般由你指定的文件大小来指定。(注意:映射文件大小为0的时候,不能创建映射区。mmap时常会有总线错误的提示,通常都是因为共享文件存储空间大小引起的)
因为你需要先打开一个文件来进行mmap进行映射
2.创建映射区的权限要小于等于打开文件的权限。
这个意思就是在映射区权限那一块你设置的权限必须比你文件打开时设置的权限小或者相等
3.映射区创建的时候隐含的对文件的一次读操作,所以文件必须要有读权限
4.偏移量必须是4k的整数倍,是一页一页的偏移的,有一个内存地址对齐。
5.文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。mmap在用户空间映射调用系统中作用很大。
6.映射区是mmu帮助你完成映射的。
7.先关闭文件是没有关系的但是必须打开了文件描述符然后才能创建一个映射区。
8.mmap创建映射区的时候建议检查返回值,出错率较高。
说完mmap了,如果在linux上查看man page可以看到下面有个mummap这个函数,这个函数就是关闭这一块共享内存区的函数,注意的是mumap传入的地址肯定要是mmap的返回的地址,不能进行指针++这种操作,因为这个返回值的步长是不定的,会出现错误。
最后需要说的一点就是如果大家在virtual box这款虚拟机上使用的时候有一个注意事项,就是映射区建立的文件是不能在虚拟机的共享文件夹里面的,这个我感觉应该是涉及到某些文件类型之类的。
大致就是这些。
下面贴一段血缘关系的mmap的使用:
#include <stdio.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
int main(void)
{
char *p;
pid_t pid;
int fd;
fd = open("temp", O_RDWR|O_CREAT|O_TRUNC, 0644);
unlink("temp");
ftruncate(fd, 200);
p = (char*)mmap(NULL, 200, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if(p == MAP_FAILED)
{
perror("mmap error");
return 0;
}
close(fd);
pid = fork();
if(pid > 0)
{
memcpy(p , "I'm parrent,I writed this word!\n", 34);
sleep(1);
}
if(pid == 0)
{
printf("%s\n",p);
wait(NULL);
}
if(pid == -1)
{
perror("fork() error");
return 0;
}
munmap(p, 200);
return 0;
}
如果非血缘关系可以查看下面两个
这是写:
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
typedef struct student{
int id;
char name[20];
char sex;
}student;
int main(int argc, char *argv[])
{
int fd;
int n;
student s1 = {1, "xiaoming", 'm'};
student *s;
if(argc < 2)
{
printf("mmap_ww error: argc error");
return 0;
}
fd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0644);
if(fd == -1)
{
perror("open() error");
return 0;
}
ftruncate(fd, sizeof(student));
s = (student*)mmap(NULL, sizeof(student), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if(s == MAP_FAILED)
{
perror("mmap error");
return 0;
}
close(fd);
n = (argv[2][0]-48);
while(n)
{
memcpy(s, &s1, sizeof(student));
s1.id++;
sleep(1);
n--;
}
sleep(20);
munmap(s, sizeof(student));
return 0;
}
这是读:
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
typedef struct student{
int id;
char name[20];
char sex;
}student;
int main(int argc, char *argv[])
{
int fd;
int n;
student *s1;
student *s;
if(argc < 2)
{
printf("mmap_rr error: argc error");
return 0;
}
fd = open(argv[1], O_RDONLY);
if(fd == -1)
{
perror("open() error");
return 0;
}
s = (student*)mmap(NULL, sizeof(student), PROT_READ, MAP_SHARED, fd, 0);
if(s == MAP_FAILED)
{
perror("mmap error");
return 0;
}
s1 = (student*)malloc(sizeof(student));
memcpy(s1, s, sizeof(student));
n = 3;
while(n)
{
printf("id = %d, name = %s, sex = %c\n",s1->id,s1->name,s1->sex);
sleep(1);
n--;
}
return 0;
}