C++共享内存小白入门指南

举报
码事漫谈 发表于 2025/12/18 19:34:20 2025/12/18
【摘要】 什么是共享内存?想象一下,你和你的室友共用一个冰箱。你们都可以往里面放东西,也可以从里面拿东西,这就是共享内存的基本概念!在C++中,共享内存是一种让不同进程(可以理解为不同的程序)能够访问同一块内存区域的技术。 为什么要使用共享内存?高效通信:进程间通信最快的方式之一数据共享:多个程序可以访问相同数据减少复制:不需要在不同进程间复制大量数据 基础知识准备在深入之前,你需要知道:进程:正在...

什么是共享内存?

想象一下,你和你的室友共用一个冰箱。你们都可以往里面放东西,也可以从里面拿东西,这就是共享内存的基本概念!在C++中,共享内存是一种让不同进程(可以理解为不同的程序)能够访问同一块内存区域的技术。

为什么要使用共享内存?

  1. 高效通信:进程间通信最快的方式之一
  2. 数据共享:多个程序可以访问相同数据
  3. 减少复制:不需要在不同进程间复制大量数据

基础知识准备

在深入之前,你需要知道:

  • 进程:正在运行的程序实例
  • 内存:程序存储数据的地方
  • 系统调用:操作系统提供的功能接口

共享内存使用步骤(Linux/Unix系统)

第一步:创建共享内存

#include <sys/ipc.h>
#include <sys/shm.h>
#include <iostream>

int main() {
    // 生成一个唯一的key
    key_t key = ftok("shmfile", 65);
    
    // 创建共享内存段,1024字节大小
    // IPC_CREAT表示创建,0666是权限(可读可写)
    int shmid = shmget(key, 1024, IPC_CREAT | 0666);
    
    if (shmid < 0) {
        std::cerr << "创建共享内存失败" << std::endl;
        return 1;
    }
    
    std::cout << "共享内存创建成功,ID: " << shmid << std::endl;
    return 0;
}

第二步:附加到共享内存

#include <sys/ipc.h>
#include <sys/shm.h>
#include <iostream>
#include <cstring>

int main() {
    key_t key = ftok("shmfile", 65);
    int shmid = shmget(key, 1024, 0666);
    
    // 附加到共享内存
    char* shared_memory = (char*)shmat(shmid, nullptr, 0);
    
    if (shared_memory == (char*)-1) {
        std::cerr << "附加到共享内存失败" << std::endl;
        return 1;
    }
    
    // 写入数据到共享内存
    std::strcpy(shared_memory, "你好,共享内存!");
    std::cout << "数据已写入共享内存" << std::endl;
    
    // 分离共享内存(但不删除)
    shmdt(shared_memory);
    
    return 0;
}

第三步:读取共享内存数据

#include <sys/ipc.h>
#include <sys/shm.h>
#include <iostream>

int main() {
    key_t key = ftok("shmfile", 65);
    int shmid = shmget(key, 1024, 0666);
    
    // 附加到共享内存
    char* shared_memory = (char*)shmat(shmid, nullptr, 0);
    
    std::cout << "从共享内存读取: " << shared_memory << std::endl;
    
    // 分离共享内存
    shmdt(shared_memory);
    
    return 0;
}

第四步:删除共享内存

#include <sys/ipc.h>
#include <sys/shm.h>
#include <iostream>

int main() {
    key_t key = ftok("shmfile", 65);
    int shmid = shmget(key, 1024, 0666);
    
    // 删除共享内存段
    shmctl(shmid, IPC_RMID, nullptr);
    
    std::cout << "共享内存已删除" << std::endl;
    return 0;
}

完整示例:进程间通信

写入进程(writer.cpp)

#include <sys/ipc.h>
#include <sys/shm.h>
#include <iostream>
#include <cstring>
#include <unistd.h>

int main() {
    // 生成key
    key_t key = ftok("shmfile", 65);
    
    // 创建共享内存(1KB大小)
    int shmid = shmget(key, 1024, IPC_CREAT | 0666);
    
    // 附加到共享内存
    char* str = (char*)shmat(shmid, nullptr, 0);
    
    std::cout << "写入进程启动,等待输入..." << std::endl;
    
    // 连续写入数据
    for (int i = 1; i <= 5; i++) {
        sprintf(str, "消息 %d", i);
        std::cout << "写入: " << str << std::endl;
        sleep(2);  // 等待2秒
    }
    
    // 写入结束标志
    strcpy(str, "结束");
    
    // 分离共享内存
    shmdt(str);
    
    return 0;
}

读取进程(reader.cpp)

#include <sys/ipc.h>
#include <sys/shm.h>
#include <iostream>
#include <cstring>
#include <unistd.h>

int main() {
    // 生成相同的key
    key_t key = ftok("shmfile", 65);
    
    // 获取共享内存
    int shmid = shmget(key, 1024, 0666);
    
    // 附加到共享内存
    char* str = (char*)shmat(shmid, nullptr, 0);
    
    std::cout << "读取进程启动,等待数据..." << std::endl;
    
    // 持续读取数据
    while (true) {
        std::cout << "读取: " << str << std::endl;
        
        // 检查是否收到结束标志
        if (strcmp(str, "结束") == 0) {
            break;
        }
        
        sleep(1);  // 每秒检查一次
    }
    
    // 分离共享内存
    shmdt(str);
    
    // 删除共享内存段
    shmctl(shmid, IPC_RMID, nullptr);
    
    std::cout << "共享内存已清理" << std::endl;
    return 0;
}

编译和运行

# 编译写入进程
g++ writer.cpp -o writer

# 编译读取进程
g++ reader.cpp -o reader

# 打开两个终端,先运行写入进程
./writer

# 在另一个终端运行读取进程
./reader

Windows下的共享内存(简单示例)

#include <windows.h>
#include <iostream>
#include <string>

int main() {
    // 创建共享内存
    HANDLE hMapFile = CreateFileMapping(
        INVALID_HANDLE_VALUE,    // 使用系统页面文件
        nullptr,                 // 默认安全属性
        PAGE_READWRITE,          // 可读可写
        0,                       // 高位文件大小
        256,                     // 低位文件大小(256字节)
        L"MySharedMemory");      // 共享内存名称
    
    // 映射到进程地址空间
    char* pBuf = (char*)MapViewOfFile(
        hMapFile,                // 共享内存句柄
        FILE_MAP_ALL_ACCESS,     // 可读可写访问
        0,
        0,
        256);
    
    // 使用共享内存
    strcpy(pBuf, "Windows共享内存示例");
    std::cout << "写入: " << pBuf << std::endl;
    
    // 清理
    UnmapViewOfFile(pBuf);
    CloseHandle(hMapFile);
    
    return 0;
}

注意事项和最佳实践

  1. 同步问题:多个进程同时访问时需要同步机制(如信号量)
  2. 内存泄漏:确保正确释放共享内存
  3. 安全性:共享内存对所有有权限的进程可见
  4. 大小限制:系统对共享内存大小有限制

常见问题解答

Q: 共享内存和普通内存有什么区别?
A: 共享内存可以被多个进程访问,普通内存只能被创建它的进程访问。

Q: 进程退出后共享内存还在吗?
A: 除非显式删除,否则共享内存会一直存在。

Q: 如何防止数据冲突?
A: 使用同步机制,如互斥锁、信号量等。

Q: 共享内存大小有限制吗?
A: 有,取决于系统配置,通常可以通过系统命令查看和调整。

学习建议

  1. 从简单的示例开始,先理解基本概念
  2. 实践编写两个进程通信的程序
  3. 学习同步机制,处理并发访问
  4. 查阅系统文档,了解具体限制和特性

记住,共享内存是强大的工具,但需要谨慎使用。确保你理解了同步和清理的重要性,避免内存泄漏和数据损坏。祝你学习顺利!

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。