可以简单地理解
共享内存:进程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)用来初始化一块内存。
/dev/zero是什么意思
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;
}