c++共享内存

什么是共享内存

共享内存是进程间通信(IPC)的一种方式,允许多个进程访问同一块内存区域,实现数据共享,它是所有IPC方式中速度最快的,因为数据不需要在进程间拷贝。

API 作用
CreateFileMapping 创建/打开一个文件映射对象(共享内存)
OpenFileMapping 打开一个已存在的文件映射对象
MapViewOfFile 将文件映射对象映射到当前进程的地址空间
UnmapViewOfFile 取消映射
CloseHandle 关闭句柄

完整示例:

服务端

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <Windows.h>
using namespace std;

#define BUF_SIZE 1024

int main() {
    char szBuffer[] = "哈哈哈,C++共享内存实战";

    // 1. 创建共享内存对象(-1 表示使用系统分页文件,不关联实际文件)
    HANDLE hMapFile = CreateFileMapping(
        INVALID_HANDLE_VALUE,  // 使用系统分页文件
        NULL,                  // 默认安全属性
        PAGE_READWRITE,        // 读写权限
        0,                     // 高32位大小
        BUF_SIZE,              // 低32位大小
        L"LSEDU"               // 共享内存名称
    );

    if (hMapFile == NULL) {
        cout << "创建共享内存失败,错误码:" << GetLastError() << endl;
        return 1;
    }

    // 2. 映射到当前进程地址空间
    LPVOID lpBase = MapViewOfFile(
        hMapFile,
        FILE_MAP_ALL_ACCESS,
        0, 0, BUF_SIZE
    );

    if (lpBase == NULL) {
        cout << "映射失败,错误码:" << GetLastError() << endl;
        CloseHandle(hMapFile);
        return 1;
    }

    // 3. 写入数据
    strcpy((char*)lpBase, szBuffer);
    cout << "【服务器】已写入数据:" << (char*)lpBase << endl;

    // 4. 等待客户端读取(按任意键退出)
    cout << "按任意键退出..." << endl;
    cin.get();

    // 5. 清理资源
    UnmapViewOfFile(lpBase);
    CloseHandle(hMapFile);

    return 0;
}

客户端

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <Windows.h>
using namespace std;

#define BUF_SIZE 1024

int main() {
    // 1. 打开已存在的共享内存对象
    HANDLE hMapFile = OpenFileMapping(
        FILE_MAP_ALL_ACCESS,  // 读写权限
        FALSE,                // 不继承句柄
        L"LSEDU"              // 共享内存名称(必须与服务器端一致)
    );

    if (hMapFile == NULL) {
        cout << "打开共享内存失败,错误码:" << GetLastError() << endl;
        return 1;
    }

    // 2. 映射到当前进程地址空间
    LPVOID lpBase = MapViewOfFile(
        hMapFile,
        FILE_MAP_ALL_ACCESS,
        0, 0, BUF_SIZE
    );

    if (lpBase == NULL) {
        cout << "映射失败,错误码:" << GetLastError() << endl;
        CloseHandle(hMapFile);
        return 1;
    }

    // 3. 读取数据
    char szBuffer[BUF_SIZE] = { 0 };
    strcpy(szBuffer, (char*)lpBase);
    cout << "【客户端】读取到数据:" << szBuffer << endl;

    // 4. 清理资源
    UnmapViewOfFile(lpBase);
    CloseHandle(hMapFile);

    return 0;
}

运行结果

先运行服务端的文件保持不退出,后运行客户端的文件,即可看到如下读取数据
c++共享内存

关键注意事项

  • 名称必须一致:CreateFileMappingOpenFileMapping 使用的名称必须完全相同(包括大小写)
  • 先创建后打开:服务器端必须先创建共享内存,客户端才能打开
  • 生命周期管理:共享内存对象的生命周期与最后一个关闭句柄的进程相关,所有进程都关闭后才会被系统销毁
  • 同步问题:共享内存本身不提供同步机制,多个进程同时读写时需要配合互斥量(Mutex)、事件(Event)等同步手段,否则会出现数据竞争

互斥量同步

如果客户端需要在服务器写入完成后再读取,可以用互斥量来同步:

服务端(创建共享内存 + 写入数据 + 互斥量同步)

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <Windows.h>
using namespace std;

#define BUF_SIZE 1024  // 共享内存缓冲区大小

int main() {
    // 要写入共享内存的数据
    char szBuffer[] = "哈哈哈,C++共享内存实战";

    // ==================== 第一步:创建共享内存对象 ====================
    // CreateFileMapping 参数说明:
    // - INVALID_HANDLE_VALUE: 表示不关联实际文件,使用系统分页文件(纯内存共享)
    // - NULL: 默认安全属性,子进程不可继承
    // - PAGE_READWRITE: 内存页保护属性,允许读写
    // - 0: 共享内存大小的高32位(BUF_SIZE 较小,高32位为0)
    // - BUF_SIZE: 共享内存大小的低32位
    // - L"LSEDU": 共享内存对象的名称(全局唯一标识,客户端通过此名称打开)
    HANDLE hMapFile = CreateFileMapping(
        INVALID_HANDLE_VALUE,
        NULL,
        PAGE_READWRITE,
        0,
        BUF_SIZE,
        L"LSEDU"
    );

    // 创建失败则输出错误码并退出
    if (hMapFile == NULL) {
        cout << "创建共享内存失败,错误码:" << GetLastError() << endl;
        return 1;
    }

    // ==================== 第二步:将共享内存映射到当前进程地址空间 ====================
    // MapViewOfFile 参数说明:
    // - hMapFile: 文件映射对象句柄
    // - FILE_MAP_ALL_ACCESS: 访问权限,允许读写
    // - 0, 0: 文件映射的偏移量(高32位和低32位),从开头映射
    // - BUF_SIZE: 要映射的字节数
    // 返回值:映射成功后返回指向共享内存的指针
    LPVOID lpBase = MapViewOfFile(
        hMapFile,
        FILE_MAP_ALL_ACCESS,
        0, 0, BUF_SIZE
    );

    if (lpBase == NULL) {
        cout << "映射失败,错误码:" << GetLastError() << endl;
        CloseHandle(hMapFile);  // 清理已创建的对象
        return 1;
    }

    // ==================== 第三步:创建互斥量(用于进程间同步) ====================
    // CreateMutex 参数说明:
    // - NULL: 默认安全属性
    // - TRUE: 初始状态为"已拥有"(即创建者拥有互斥量),客户端打开后会阻塞等待
    // - L"DataReadyMutex": 互斥量名称(全局唯一标识)
    HANDLE hMutex = CreateMutex(NULL, TRUE, L"DataReadyMutex");

    if (hMutex == NULL) {
        cout << "创建互斥量失败,错误码:" << GetLastError() << endl;
        UnmapViewOfFile(lpBase);
        CloseHandle(hMapFile);
        return 1;
    }

    // ==================== 第四步:向共享内存写入数据 ====================
    // 将数据拷贝到共享内存区域(lpBase 指向共享内存的起始地址)
    strcpy((char*)lpBase, szBuffer);
    cout << "【服务器】已写入数据:" << (char*)lpBase << endl;

    // ==================== 第五步:释放互斥量,通知客户端 ====================
    // ReleaseMutex 将互斥量状态从"已拥有"改为"未拥有"
    // 此时正在等待该互斥量的客户端会被唤醒,继续执行
    ReleaseMutex(hMutex);
    cout << "【服务器】已释放互斥量,通知客户端可以读取" << endl;

    // ==================== 第六步:等待用户操作后退出 ====================
    cout << "按任意键退出..." << endl;
    cin.get();

    // ==================== 第七步:清理资源(按创建的逆序释放) ====================
    CloseHandle(hMutex);           // 关闭互斥量句柄
    UnmapViewOfFile(lpBase);       // 取消内存映射
    CloseHandle(hMapFile);         // 关闭文件映射对象句柄

    return 0;
}

客户端(打开共享内存 + 读取数据 + 互斥量同步)

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <Windows.h>
using namespace std;

#define BUF_SIZE 1024  // 共享内存缓冲区大小(需与服务器端一致)

int main() {
    // ==================== 第一步:打开已存在的共享内存对象 ====================
    // OpenFileMapping 参数说明:
    // - FILE_MAP_ALL_ACCESS: 请求的访问权限(读写)
    // - FALSE: 句柄不可被子进程继承
    // - L"LSEDU": 共享内存名称(必须与服务器端 CreateFileMapping 中的名称完全一致)
    HANDLE hMapFile = OpenFileMapping(
        FILE_MAP_ALL_ACCESS,
        FALSE,
        L"LSEDU"
    );

    // 打开失败(通常是因为服务器端未运行或已退出)
    if (hMapFile == NULL) {
        cout << "打开共享内存失败,错误码:" << GetLastError() << endl;
        return 1;
    }

    // ==================== 第二步:将共享内存映射到当前进程地址空间 ====================
    LPVOID lpBase = MapViewOfFile(
        hMapFile,
        FILE_MAP_ALL_ACCESS,
        0, 0, BUF_SIZE
    );

    if (lpBase == NULL) {
        cout << "映射失败,错误码:" << GetLastError() << endl;
        CloseHandle(hMapFile);
        return 1;
    }

    // ==================== 第三步:打开互斥量 ====================
    // OpenMutex 参数说明:
    // - SYNCHRONIZE: 请求同步访问权限(只需等待/释放,不需要修改互斥量)
    // - FALSE: 句柄不可继承
    // - L"DataReadyMutex": 互斥量名称(必须与服务器端 CreateMutex 中的名称一致)
    HANDLE hMutex = OpenMutex(SYNCHRONIZE, FALSE, L"DataReadyMutex");

    if (hMutex == NULL) {
        cout << "打开互斥量失败,错误码:" << GetLastError() << endl;
        UnmapViewOfFile(lpBase);
        CloseHandle(hMapFile);
        return 1;
    }

    // ==================== 第四步:等待服务器端通知 ====================
    // WaitForSingleObject 会阻塞当前线程,直到:
    // - 互斥量变为"未拥有"状态(服务器端调用了 ReleaseMutex)
    // - 或者超时(INFINITE 表示永不超时)
    cout << "【客户端】正在等待服务器端数据..." << endl;
    WaitForSingleObject(hMutex, INFINITE);
    cout << "【客户端】收到通知,开始读取数据" << endl;

    // ==================== 第五步:从共享内存读取数据 ====================
    char szBuffer[BUF_SIZE] = { 0 };  // 初始化为全0
    strcpy(szBuffer, (char*)lpBase);  // 从共享内存拷贝数据到本地缓冲区
    cout << "【客户端】读取到数据:" << szBuffer << endl;

    // ==================== 第六步:清理资源(按创建的逆序释放) ====================
    CloseHandle(hMutex);           // 关闭互斥量句柄
    UnmapViewOfFile(lpBase);       // 取消内存映射
    CloseHandle(hMapFile);         // 关闭文件映射对象句柄

    return 0;
}

c++共享内存

概念 说明
INVALID_HANDLE_VALUE 表示不关联实际磁盘文件,使用系统分页文件实现纯内存共享
CreateFileMapping vs OpenFileMapping 前者创建,后者打开;名称必须完全一致
MapViewOfFile 将共享内存"映射"到进程自己的地址空间,返回一个指针,之后就像操作普通内存一样
CreateMutex(..., TRUE, ...) 第二个参数 TRUE 表示创建者立即拥有互斥量,其他人打开后会阻塞
ReleaseMutex 释放互斥量,唤醒等待者
WaitForSingleObject(..., INFINITE) 无限等待,直到被唤醒
资源释放顺序 建议按创建的逆序释放:先关互斥量 → 取消映射 → 关文件映射

总结

使用共享内存的核心原则

适合本机进程间大量、高频的数据交换
必须配合同步机制(互斥量、事件、信号量等),否则会出现数据竞争
不适合跨机器通信,跨机器场景用 SocketRPC
注意生命周期管理,避免进程异常退出导致共享内存"泄漏"

概括一句话

只要是在同一台机器上,多个进程需要频繁交换大量数据,共享内存就是最优选择。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐