多进程共享内存
共享内存:
在内存模型中,内核空间的下面有一块空间叫做内存映射段,包括文件映射(如映射动态链接库,程序运行时,将动态库加载到内存,并映射到程序的地址空间)、匿名映射,实现内存共享。
mmap:一种内存映射文件的方法,将内核中的特定部分内存映射到用户级进程中去,相比普通的read/write少一次拷贝,内核直接把文件数据从磁盘拷贝到共享内存就用户就行访问,使得这份数据不需要同时保留在两个页缓冲中;而write需要先从磁盘拷贝到页缓冲,再从页缓冲拷贝到用户进程;
所以你会发现文件利用读写函数下载时,内存变少,buff/cache变大
重定向
本质是修改该进程中files_struct的元素指向。
实现
注意:
- vfork是直接共享父进程的虚拟空间和物理空间,类似于线程。
- fork不共享父进程的空间,会进行正文段、数据段、堆、栈的写时复制
- fork()时,子进程和父进程是共享内存的,但是内存只要是共享的,那一定是写保护的
- 当父进程和子进程进行写操作时,内核把这个页复制到一个新的页面,标记为对该进程可写,原来的页面仍然是写保护
- 一个写保护的页面只有一个属主时,当这个属主进程访问这个页面时,内核将这个页面标记为对这个进程可写
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h> // 共享内存
void *shm_mmap_alloc(int size)
{
/**
* PROT_READ|PROT_WRITE:对文件可读可写,不可执行
* MAP_ANON | MAP_SHARED: 匿名共享,就像是匿名管道通信
* fd=open(name, flag, mode); 这里为-1表示匿名文件,通过ls是无法查看的,就像匿名的管道无法查看,0是标准输入->键盘,1是标准输出->显示器,2是标准错误->显示器
*/
// 多个进程可以读同一个文件
void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_SHARED, -1, 0);
// 也可以用下面这种:/dev/zero设备像个黑洞,写多少数据都会被吞掉
// int fd = open("/dev/zero", O_RDWR);
// void *addr = mmap(NULL, size, PROT_READ|PROT_WRITE,
// MAP_SHARED, fd, 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[1024];父进程是打印不出信息的
char *addr = (char *)shm_mmap_alloc(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("parent: %s\n", addr);
sleep(1);
}
}
shm_mmap_free(addr, 1024);
return 0;
}
除了mmap,还有shmget接口实现进程间共享内存通信