多进程之间、使用共享内存、实现图片的数据通信:包括POSIX共享内存(shm_open 和 mmap虚拟内存)、系统调用(shmat物理存储器)、内存映射文件等方法

一、共享内存(SHM)
在这里插入图片描述

像上图所示,当进程 P1 向其虚拟内存中的区域 1 写入数据时,进程 2 就能同时在其虚拟内存空间的区域 2 看见这些数据,中间没有经过任何的转发,效率极高。
使用共享内存的一般步骤是:

    1,获取共享内存对象的 ID
    2,将共享内存映射至本进程虚拟内存空间的某个区域
    3,当不再使用时,解除映射关系
    4,当没有进程再需要这块共享内存时,删除它。

方法总结

共享内存是进程间通信(IPC)的重要方式之一,可以让多个进程访问相同的内存区域,从而实现数据共享。实现共享内存的方式有多种,主要包括以下几种:

POSIX 共享内存 (POSIX Shared Memory)

使用 shm_open 和 mmap 等函数来创建和管理共享内存段。
POSIX 共享内存可以通过名字标识,多个进程可以通过名字来访问同一个共享内存段。
需要使用 shm_unlink 来删除共享内存对象。
mmap:它是一个系统调用,用于在用户空间和内核空间之间进行文件映射。

System V 共享内存 (System V Shared Memory)

使用 shmget、shmat、shmdt 和 shmctl 等函数来创建和管理共享内存段。
共享内存段通过一个整数键来标识,进程通过这个键来访问共享内存段。
System V 共享内存提供了更多的控制选项,但编程接口相对复杂。
shmat是Linux系统中的一个重要的内存管理函数

匿名映射(Anonymous Mapping)

使用 mmap 函数,可以在多个进程之间创建匿名共享内存区域。
通常通过 fork 创建子进程时,共享的匿名内存区域会自动继承。

内存映射文件(Memory Mapped Files)

使用 mmap 函数将文件映射到进程的地址空间,不同进程可以通过映射同一个文件来实现共享内存。
文件映射提供了一种持久化的数据共享方式,但需要文件系统的支持。

Windows 共享内存

使用 Windows API 提供的 CreateFileMapping 和 MapViewOfFile 函数来创建和管理共享内存段。
通过命名的内存映射文件对象可以在不同进程间共享内存。
需要使用 CloseHandle 来释放资源。

Boost.Interprocess (C++ 库)

Boost 库提供了跨平台的共享内存实现,使用 boost::interprocess::shared_memory_object 和 boost::interprocess::mapped_region 等类来管理共享内存。
提供了更高层次的封装,简化了共享内存的使用。

Python 的 multiprocessing 模块

Python 的 multiprocessing 模块提供了共享内存的支持,如 multiprocessing.Array 和 multiprocessing.Value。
适用于 Python 的多进程编程,简单易用。

每种共享内存方式都有其特点和适用场景,选择具体方式时需要根据系统平台、应用需求和编程语言等因素进行权衡。

举例:内存映射文件(Memory Mapped Files)

先用open函数打开一个文件,然后调用mmap函数把得到的描述符映射到当前进程地址空间中。这种方式访问速度相对较慢,因为需要内核同步或异步更新到文件系统中。

#include <stdio.h>  
#include <stdlib.h>  
#include <fcntl.h>  
#include <sys/mman.h>  
#include <unistd.h>  
  
int main() {
     
    // 打开文件  
    int fd = open("example.txt", O_RDWR);  
    if (fd == -1) {
     
        perror("Error opening file");  
        exit(EXIT_FAILURE);  
    }  
  
    // 获取文件大小  
    struct stat sb;  
    if (fstat(fd, &sb) == -1) {
     
        perror("Error getting the file size");  
        exit(EXIT_FAILURE);  
    }  
    off_t length = sb.st_size; // 文件大小,单位是字节  
  
    // 映射内存到进程的地址空间  
    char* map = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);  
    if (map == MAP_FAILED) {
     
        perror("Error mmapping the file");  
        exit(EXIT_FAILURE);  
    }  
  
    // 打印映射的内存内容,即文件内容  
    for (off_t i = 0; i < length; i++) {
     
        printf("%c", map[i]); // 打印每个字符,即文件内容  
    }  
    printf("\n");  
  
    // 释放内存映射和文件描述符  
    if (munmap(map, length) == -1) {
     
        perror("Error un-mmapping the file");  
        exit(EXIT_FAILURE);  
    }  
    close(fd);  
    return 0;  
}
  • open函数用于打开文件,其返回值是文件描述符。如果打开失败,则返回-1。第二个参数O_RDWR表示以读写模式打开文件。
  • fstat函数用于获取文件的大小,其返回值是stat结构体,其中st_size成员表示文件大小(单位是字节)。如果获取失败,则返回-1。
  • mmap函数用于将文件映射到进程的地址空间。第一个参数是映射区域的起始地址,通常为NULL。第二个参数是映射区域的长度。第三个参数是保护标志,这里设置为读、写和共享(可读、可写、可被其他进程共享)。第四个参数是映射对象的类型,这里设置为共享内存。第五个参数是文件描述符。第六个参数是文件映射的偏移量。如果映射成功,则返回映射区域的指针;否则返回MAP_FAILED。
  • munmap函数用于释放内存映射。第一个参数是映射区域的指针。第二个参数是映射区域的长度。如果释放成功,则返回0;否则返回-1。

举例:POSIX 共享内存

先用shm_open打开一个Posix IPC名字(也可以是文件系统中的一个路径名),然后调用mmap将返回的描述符映射到当前进程的地址空间。

#include <stdio.h>  
#include <stdlib.h>  
#include <fcntl.h>  
#include <sys/mman.h>  
#include <unistd.h>  
  
#define SHM_SIZE 1024  // 共享内存大小  
  
int main() {
     
    int fd;  
    void *map_ptr;  
  
    // 打开共享内存对象,以读写模式打开,不创建新对象,如果对象不存在则返回-1  
    fd = shm_open("/Posix IPC", O_RDWR | O_CREAT, 0666);  
    if (fd == -1) {
     
        perror("shm_open");  
        exit(EXIT_FAILURE);  
    }  
  
    // 调整共享内存对象的大小,这里将其设置为1024字节  
    if (ftruncate(fd, SHM_SIZE) == -1) {
     
        perror("ftruncate");  
        exit(EXIT_FAILURE);  
    }  
  
    // 将共享内存对象的描述符映射到当前进程的地址空间,map_ptr指向的就是这块内存的起始地址  
    map_ptr = mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);  
    if (map_ptr == MAP_FAILED) {
     
        perror("mmap");  
        exit(EXIT_FAILURE);  
    }  
  
    // 现在可以在map_ptr指向的内存区域进行读写操作了,这就像操作普通的内存一样简单  
    // ... 写入数据到 map_ptr 指向的内存区域 ...  
    // ... 从 map_ptr 指向的内存区域读取数据 ...  
  
    // 当进程不再需要访问共享内存时,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hali_Botebie

文中错误请不吝指正!!!!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值