进程通信之共享内存(Windows)

进程通信的基本概念

进程通信就是不同进程之间互相传递数据和消息,让它们能协同工作。就像人们之间需要交流信息来合作完成任务一样,进程也需要通信来一起完成复杂的操作。常见的有以下几种:

  • 管道 :就像两个进程之间拉了一根水管,数据可以在这根管子里单向流动。一个进程向管道写入数据,另一个进程从管道读取数据。
  • 套接字 :类似于通信的 “隧道”,可以在不同设备上的进程之间进行网络通信。通过套接字,进程可以跨越网络传递数据。
  • 共享内存 :效率极高,相当于给多个进程共享一块 “公共区域”,各进程可直接在此区域读写数据,快速实现数据交换。

我们这次重点说共享内存通信。之前我们讲过内存映射文件,它允许将文件内容映射到内存地址空间,使多个进程像操作内存一样读写文件内容,共享内存与之类似,只不过共享内存主要用于进程间通信,无须涉及文件操作,直接在内存中开辟共享区域供多个进程访问。

使用示例

核心步骤

  • 1)取唯一名称 :为共享内存和事件对象取唯一名称,避免命名冲突。
  • 2)映射内存 :使用 MapViewOfFile 将共享内存映射到进程地址空间。
  • 3)读写数据 :按约定的数据结构进行读写操作。
  • 4)发送通知 :生产者写完数据后,通过事件对象通知消费者。

数据结构定义

struct DataHeader {
    short dataType;       // 数据类型
    short width;          // 图像宽度
    short height;         // 图像高度
    short frameIndex;     // 帧号
};

const int SHM_SIZE = sizeof(DataHeader) + 20000 * sizeof(short);
const wchar_t* SHM_NAME = L"SuperSharingMemory";
const wchar_t* EVENT_NAME = L"DataIsReady";

生产者写数据

void ProducerWriteData(short* pixelData, int w, int h, int frame) {
    // 1. 创建或打开共享内存
    HANDLE hShm = CreateFileMapping(
        INVALID_HANDLE_VALUE,
        NULL,
        PAGE_READWRITE,
        0, SHM_SIZE >> 31,
        SHM_SIZE & 0xFFFFFFFF,
        SHM_NAME
    );

    // 2. 映射共享内存到进程地址空间
    char* shmAddr = (char*)MapViewOfFile(hShm, FILE_MAP_ALL_ACCESS, 0, 0, SHM_SIZE);

    // 3. 填写数据头部信息
    DataHeader* header = (DataHeader*)shmAddr;
    header->dataType = 1;
    header->width = (short)w;
    header->height = (short)h;
    header->frameIndex = (short)frame;

    // 4. 写入像素数据
    short* dataStart = (short*)(shmAddr + sizeof(DataHeader));// 计算像素数据起始地址
    memcpy(dataStart, pixelData, w * h * sizeof(short));// 直接内存拷贝

    // 5. 通知消费者数据已准备好
    HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, EVENT_NAME);
    SetEvent(hEvent);	// 触发事件(通知消费者)
    CloseHandle(hEvent);// 关闭事件句柄

    // 6. 清理资源(注意)
    UnmapViewOfFile(shmAddr);	// 解除内存映射
    CloseHandle(hShm);	// 关闭共享内存句柄
}

消费者读数据

void ConsumerReadData() {
    // 1. 打开共享内存
    HANDLE hShm = OpenFileMapping(FILE_MAP_READ, FALSE, SHM_NAME);

    // 2. 映射共享内存到进程地址空间
    char* shmAddr = (char*)MapViewOfFile(hShm, FILE_MAP_READ, 0, 0, SHM_SIZE);

    // 3. 等待数据准备就绪的通知
    HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, EVENT_NAME);
    WaitForSingleObject(hEvent, INFINITE);	// 阻塞等待事件变为有信号状态

    // 4. 读取数据
    DataHeader* header = (DataHeader*)shmAddr;
    short* pixelData = (short*)(shmAddr + sizeof(DataHeader));	// 获取像素数据起始位置
    printf("收到数据:宽度%d,高度%d,帧号%d\n", header->width, header->height, header->frameIndex);

    // 5. 清理资源
    UnmapViewOfFile(shmAddr);  // 解除内存映射
    CloseHandle(hShm);         // 关闭共享内存句柄
    CloseHandle(hEvent);       // 关闭事件句柄
}

总结

共享内存通信相当于两个程序共用一块内存区域:

  • 生产者写入数据后,通过事件通知消费者。
  • 消费者收到通知后,从共享内存中读取数据。
  • 整个过程数据无需拷贝,传输效率极高。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值