boost::interprocess 32 位和 64 位进程之间的共享内存
Posted
技术标签:
【中文标题】boost::interprocess 32 位和 64 位进程之间的共享内存【英文标题】:boost::interprocess shared memory between 32 and 64 bit processes 【发布时间】:2013-08-30 12:59:11 【问题描述】:我正在尝试让 boost::interprocess 在 32 位和 64 位进程之间共享内存。 This bug tracker entry 建议这在我使用的 Boost 1.49 中可能是可能的。
作为测试,我尝试共享一个无符号整数。这是一个带有两个按钮的简单 Qt 应用程序。
#define SHARED_MEMORY_NAME "My shared memory"
#define SHARED_VAR_NAME "testVar"
namespace bip = boost::interprocess;
void on_createMemButton_clicked()
std::cout << "sizeof(unsigned int): " << sizeof(unsigned int) << std::endl;
bip::shared_memory_object::remove(SHARED_MEMORY_NAME);
bip::managed_shared_memory mem(bip::create_only, SHARED_MEMORY_NAME, 12345);
mem.construct<unsigned int>(SHARED_VAR_NAME)(42);
std::cout << "Created shared memory " << SHARED_MEMORY_NAME << std::endl;
void on_accessMemButton_clicked()
try
std::cout << "sizeof(unsigned int): " << sizeof(unsigned int) << std::endl;
bip::managed_shared_memory mem(bip::open_only, SHARED_MEMORY_NAME);
std::pair<unsigned int*, size_t> p = mem.find<unsigned int>(SHARED_VAR_NAME);
std::cout<< "got " << p.second << " numbers " << std::endl;
if (p.second > 0)
std::cout << "first number is: " << *p.first << std::endl;
bip::shared_memory_object::remove(SHARED_MEMORY_NAME);
catch (bip::interprocess_exception e)
std::cout << "Shared mem " << SHARED_MEMORY_NAME << " not found" << std::endl;
如果我从具有相同位数的进程创建或访问共享内存,它可以正常工作。但是,如果我在 64 位进程中创建内存,并从 32 位进程中读取,则该进程进入 managed_shared_memory::find()
函数并且永远不会回来。如果我反过来尝试,64 位进程在managed_shared_memory::find()
中再次失败,这次是访问冲突。使用managed_windows_shared_memory
产生了相同的结果。
有什么办法可以做到吗?
【问题讨论】:
多么奇怪……在 Unix 风格的操作系统上,我绝对希望它能够工作,但我不知道它在 Windows 下是如何工作的。 在跨架构代码的情况下,您应该使用uint32_t
而不是 unsigned int
,这可能是一个问题,具体取决于您的编译器。我也在使用 Visual c++ 10.0 编译器在 Windows 上使用 boost ipc 进行 x86 6432 通信,使用 boost 1.50,它就像一个魅力。
我遇到了同样的问题。有结果吗?
@Viatorus 我们最终直接使用了 Windows API(CreateFileMapping
、CreateMutex(NULL, FALSE, ...)
)。
【参考方案1】:
我遇到了同样的问题。我有一个在另一个进程中运行的 DLL 和一个单独编译的控制器应用程序。我的 find() 和 find_or_construct() 会挂起,使它看起来像死锁。更改为 null_mutex_family 没有任何效果。
问题原来是用于编译 DLL 与控制器应用程序的 char 类型。将两者都设置为使用多字节字符为我修复了它(使用 MSVC)。
我将这一行添加到我的代码中,这样它就永远不会再像那样咬我,就在访问我的 managed_shared_memory 实例之前。
if (sizeof(char) != 2) throw std::exception("Set your chars right");
如果您尝试从使用另一种类型的应用程序中查找和使用一种类型的 char 构造的对象,boost 将陷入无限循环(我没有耐心尝试查找)。
【讨论】:
sizeof(char)
始终为1
,因为sizeof
的度量单位为char
s。你的意思是sizeof(TCHAR)
?另请查看 static_assert
以获得编译时而非运行时验证。【参考方案2】:
我在 Windows 上遇到了同样的问题,在 VS2019 中使用 vc142 工具集进行编译。我使用了 boost 1.73,但我认为 boost 1.60+ 也可以。此外,我使用的是 Windows 托管内存,而不是原始提问者使用的常规托管内存。但我认为我的解决方案仍然适用。
在编译时注意到这一点后,我能够解决它
using ManagedShMem = bip::managed_windows_shared_memory;
ManagedShMem segment(bip::open_or_create, pcShMemName, uiMemSize, 0, perms); // will have issues, if used for crossplatform interaction.
在我的 32 位平台上,它有效地调用了这个构造函数:
boost::interprocess::basic_managed_windows_shared_memory<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index>::basic_managed_windows_shared_memory<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index>(boost::interprocess::open_or_create_t __formal, const char * name, unsigned int size, const void * addr, const boost::interprocess::permissions & perm);
而在 64 位平台上:
boost::interprocess::basic_managed_windows_shared_memory<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>::basic_managed_windows_shared_memory<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>(boost::interprocess::open_or_create_t __formal, const char * name, unsigned __int64 size, const void * addr, const boost::interprocess::permissions & perm);
如您所见,offset_ptr 的模板参数是不同的,两者之间。这会导致 32 位和 64 位进程之间的二进制布局假设有所不同,从而进一步导致使用共享内存的问题。
您需要做的就是使您的托管细分类型在各个平台上完全一致。所以,我的解决方案很简单——只需明确列出模板参数并与 64 位平台兼容即可:
using ManagedShMem = bip::basic_managed_windows_shared_memory
<char,
boost::interprocess::rbtree_best_fit<
boost::interprocess::mutex_family,
boost::interprocess::offset_ptr<
void,
__int64,
unsigned __int64,
0>,
0>,
boost::interprocess::iset_index>;
ManagedShMem segment(bip::open_or_create, pcShMemName, uiMemSize, 0, perms); // now works well on both platforms!
之后,我可以通过共享内存段让我的 32 位进程与我的 64 位进程通信(反之亦然)。
附:另外,请记住,32 位平台限制了您可以访问的内存量。根据经验,对于 Windows 32 位进程,您不能获得超过 2 GB(虽然我对 1.5 GB 没有问题,但这取决于许多其他因素)的共享内存。这意味着如果您决定在 64 位进程上分配 2 GB 或更多空间(这很容易实现),您在 32 位进程上的段构造函数将获得异常,因为 boost(通过 Win32 API)将拒绝映射这么大的内存块。
【讨论】:
以上是关于boost::interprocess 32 位和 64 位进程之间的共享内存的主要内容,如果未能解决你的问题,请参考以下文章
boost::interprocess::managed_mapped_file 如何包含弹性向量?
boost::interprocess::string 转换为 char*
boost::interprocess::interprocess_condition::wait 在等待时不会原子地解锁互斥锁