可以简单地理解
共享内存:进程A中的一块内存空间和进程B中操作的一块内存空间是同一块内存空间
更详细的原理可以参考,下面主要是如何使用mmap去实现共享内存。
一、mmap参数
通过man手册可以知道
addr
:共享内存的地址,如果为NULL,则会自动分配一块内存
length
:共享内存的长度
prot
:内存保护的一些flags(比如说:匿名,读,写权限等)
flags
:是否对其他进程可见,更新是否会传递到底层文件
fd
:文件描述符(用于对内存初始化)
offset
:偏移量(用于初始化,offset从fd哪个位置开始读取,length可以表示读取长度)
二、内存不共享情况
利用malloc
去创建一块内存
利用fork()
去创建一个子进程,子进程将字符写入到共享内存中,主进程将从内存中读数据。(能读到数据就说明,不同进程之间共享了数据)
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/mman.h> #include <fcntl.h> //创建共享内存 void *shm_mmap_alloc(int size) { void *addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); if (addr == MAP_FAILED) { return NULL; } return addr; } //释放共享内存 int shm_mmap_free(void *addr, int size) { return munmap(addr, size); } int main() { char* addr=(char*)malloc(1024*1024); pid_t pid = fork();//创建子进程 if (pid == 0) {//子进程中写字符 int i = 0; while (i < 26) { addr[i] = 'a' + i; addr[++i] = '\0'; sleep(1); } } else if (pid > 0) {//父进程中读字符 int i = 0; while (i ++ < 26) { printf("client : %s\n", addr); sleep(1); } } }
可以发现主进程读不到任何数据
三、内存共享
在其他不变的情况下,通过mmap
来创建一块共享内存,munmap
去释放一块共享内存。
用mmap
创建内存代替malloc
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/mman.h> #include <fcntl.h> //创建共享内存 void *shm_mmap_alloc(int size) { void *addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); if (addr == MAP_FAILED) { return NULL; } return addr; } //释放共享内存 int shm_mmap_free(void *addr, int size) { return munmap(addr, size); } int main() { char *addr= (char *)shm_mmap_alloc(1024 * 1024); pid_t pid = fork();//创建子进程 if (pid == 0) {//子进程中写字符 int i = 0; while (i < 26) { addr[i] = 'a' + i; addr[++i] = '\0'; sleep(1); } } else if (pid > 0) {//父进程中读字符 int i = 0; while (i ++ < 26) { printf("client : %s\n", addr); sleep(1); } } shm_mmap_free(addr, 1024); }
运行后,可以发现主进程能读出子进程里的数据,因此是内存共享的。
换种写法
利用从"/dev/zero"中读数据,读到的数据都是空的,都是0,因此可以利用 该文件描述符(fd)用来初始化一块内存。
void *shm_mmap_alloc(int size) { int fd = open("/dev/zero", O_RDWR); void *addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); close(fd); if (addr == MAP_FAILED) { return NULL; } return addr; }