共享内存进程间通信
我使用shmget
分配了一块共享内存。共享内存进程间通信
然后,我使用shmat
分别将共享内存附加到进程A和进程B.我假设由shmat
返回的A和B的句柄(即A和B内映射到实际共享内存的地址)是不同的。
我们假设A和B的手柄分别定义为char* p
和char* q
。 我的问题是如果我们在进程A中写入一个对象到地址p + sizeof(anotherObject)
,我们可以期望在进程B中的地址q + sizeof(anotherObject)
处获得相同的对象吗?
我想是这样,但并非100%确定。如果是这样,这个通信或映射机制是如何实现的,因为我们知道p + sizeof(anotherObject)
和q + sizeof(anotherObject)
指的是不同的内存位置?
现代处理器使用虚拟地址空间。您在程序中使用的地址不是对象的“真实”地址,操作系统和处理器将内存页面映射到地址范围,并将其用作“内存”。
创建共享内存仅仅意味着操作系统将同一内存页映射到两个或更多不同进程的地址空间。两个进程中的两个指针不具有相同数值的事实意味着什么,即使不同进程中的指针具有相同的数值,它们通常也指向不同的内存位置。
关于将“对象”写入内存,首先必须“序列化”它。我提到了不同进程中的指针彼此不兼容。如果你的对象有任何指针成员或其他可能包含指针的对象,你必须想出一种方法来将这些指针替换为实际数据,因为一旦你从另一个线程读取对象,那些指针就会像垃圾。
请注意,C++ std :: sting,std :: vector和其他容器以及任何虚拟对象(具有虚函数的对象)都有指针。所以如果你想传递一个字符串,你需要将它作为一个字符序列写入共享内存中,并在另一侧以相同的方式读取。
+1对我的理解非常有帮助。 –
你能写共享内存区域中的对象的二进制表示吗?是。
您是否可以通过访问存储在共享内存中的二进制表示形式安全地使用另一个程序中的对象?有时候,但不一般。
这些规则类似于将串行化的二进制表示写出到磁盘或通过线路。您必须确保处理指向其他对象的指针以及所有非POD成员。例如,std::string
实例有一个指针指向分配的存储器,其中:
- 可能不是在共享存储器中的区域
- 可能没有在其他过程中的相同的地址(例如,该数据是在共享存储器中,但共享内存区域在两个进程中映射到不同的基址)。
于是,一种简单的规则是:如果X
是什么,你不能:
std::ofstream file("foo.bin",std::ios::binary);
file.write(reinterpret_cast<const char*>(&X), sizeof(X));
那么你不能安全地写出来到共享内存中。
备注:即使数据是POD类型,也不能认为写出它是安全的。在某些操作系统上,可以运行几种不同类型的进程(例如32位和64位进程)。在这种情况下,使用类型如int
可能在两个过程中都不相同。给定一个特定的操作系统,一个特定的编译器和特定的编译设置,就有可能推导出一种可靠的方式来编写这种POD类型。如果这个环境可以改变,就避免像瘟疫那样做。
您可以使用固定宽度的POD(如int32_t和uint8_t)来确保32位和64位进程都可以使用它们。 – 2011-11-29 22:07:11
@WTP:仍不能保证两个进程都使用相同的编译器和相同的对齐方式。这比看起来更微妙。因此,实现这一点*可能*,但不*保证*。 –
考虑使用Boost.Interprocess - 有一个文档可以回答像你这样的问题。 – Simon
考虑使用现代接口'shm_open'和'mmap'来完成这样的任务。他们限制较少,更容易处理。 –