多进程共享内存

共享内存:

在内存模型中,内核空间的下面有一块空间叫做内存映射段,包括文件映射(如映射动态链接库,程序运行时,将动态库加载到内存,并映射到程序的地址空间)、匿名映射,实现内存共享。


多进程共享内存 python 多进程共享内存读取_linux

mmap:一种内存映射文件的方法,将内核中的特定部分内存映射到用户级进程中去,相比普通的read/write少一次拷贝,内核直接把文件数据从磁盘拷贝到共享内存就用户就行访问,使得这份数据不需要同时保留在两个页缓冲中;而write需要先从磁盘拷贝到页缓冲,再从页缓冲拷贝到用户进程;

所以你会发现文件利用读写函数下载时,内存变少,buff/cache变大

重定向

本质是修改该进程中files_struct的元素指向。

多进程共享内存 python 多进程共享内存读取_共享内存_02

实现

注意:

  • 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接口实现进程间共享内存通信