能否跨进程传递含成员函数的C++类实例?求POSIX共享内存实现示例
问题解答
1. 需求是否可行?
可行,但需满足以下关键限制:
- 两个进程必须使用完全一致的类定义:包括成员变量的类型、顺序,成员函数的声明,否则会因内存布局不匹配导致数据访问错误。
- 类不能包含虚函数:虚函数依赖虚表指针,而不同进程的虚表地址属于独立地址空间,直接调用会触发非法内存访问。
- 成员函数需为内联函数,或在两个进程中拥有完全相同的实现:成员函数的代码不在共享内存中,调用时实际执行的是当前进程本地的函数逻辑,仅操作共享内存中的数据成员。
2. POSIX共享内存实现示例
步骤1:共享类定义(a.h)
两个进程都需要包含这个头文件,确保类的内存布局一致:
#ifndef A_H #define A_H class A { public: int data; // 内联构造函数 A() : data(0) {} // 内联成员函数,逻辑在每个进程中都会编译生成 int f() { return data * 2; } }; #endif
步骤2:进程1代码(创建共享内存并初始化实例)
#include <iostream> #include <sys/mman.h> #include <fcntl.h> #include <unistd.h> #include "a.h" int main() { // 创建POSIX共享内存对象 int shm_fd = shm_open("/my_shared_memory", O_CREAT | O_RDWR, 0666); if (shm_fd == -1) { perror("shm_open failed"); return 1; } // 设置共享内存大小为类A的字节数 if (ftruncate(shm_fd, sizeof(A)) == -1) { perror("ftruncate failed"); close(shm_fd); shm_unlink("/my_shared_memory"); return 1; } // 将共享内存映射到当前进程地址空间 A* a = static_cast<A*>(mmap(nullptr, sizeof(A), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0)); if (a == MAP_FAILED) { perror("mmap failed"); close(shm_fd); shm_unlink("/my_shared_memory"); return 1; } // 使用placement new在共享内存中构造A的实例 new(a) A(); a->data = 10; std::cout << "进程1: 设置a.data = " << a->data << ", a.f()返回值: " << a->f() << std::endl; // 等待进程2操作完成 std::cout << "按回车键继续清理资源..." << std::endl; std::cin.get(); // 手动调用析构函数销毁实例 a->~A(); // 解除内存映射 munmap(a, sizeof(A)); close(shm_fd); // 删除共享内存对象 shm_unlink("/my_shared_memory"); return 0; }
步骤3:进程2代码(访问共享内存并调用成员函数)
#include <iostream> #include <sys/mman.h> #include <fcntl.h> #include <unistd.h> #include "a.h" int main() { // 打开已创建的共享内存对象 int shm_fd = shm_open("/my_shared_memory", O_RDWR, 0666); if (shm_fd == -1) { perror("shm_open failed"); return 1; } // 将共享内存映射到当前进程地址空间 A* a = static_cast<A*>(mmap(nullptr, sizeof(A), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0)); if (a == MAP_FAILED) { perror("mmap failed"); close(shm_fd); return 1; } // 调用成员函数,操作共享内存中的数据 std::cout << "进程2: 读取a.data = " << a->data << ", a.f()返回值: " << a->f() << std::endl; // 修改数据并再次调用 a->data = 20; std::cout << "进程2: 更新a.data = " << a->data << ", a.f()返回值: " << a->f() << std::endl; // 解除内存映射 munmap(a, sizeof(A)); close(shm_fd); return 0; }
编译与运行
- 编译命令(需链接lrt库):
g++ process1.cpp -o process1 -lrt g++ process2.cpp -o process2 -lrt - 运行:先启动
./process1,在它等待输入时,另开终端启动./process2,观察输出后回到进程1按回车完成清理。
核心原理
共享内存仅存储类的数据成员,成员函数的代码在每个进程的本地代码段中。调用a->f()时,实际是将共享内存中实例的地址作为this指针,执行当前进程本地的函数逻辑,从而操作共享内存中的数据。
内容的提问来源于stack exchange,提问作者HyunWoo Lee
相关产品推荐
相关产品推荐

