boost::32位和64位进程之间的进程间共享内存

boost::interprocess shared memory between 32 and 64 bit processes

本文关键字:进程 共享 内存 之间 64位 boost 32位      更新时间:2023-10-16

我正在尝试使用boost::interprocess在32位和64位进程之间共享内存。这个bug跟踪器条目表明,这可能在我使用的Boost 1.49中实现。

作为一个测试,我尝试共享一个未签名的int。这是一个带有两个按钮的简单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()中再次失败,这次是访问冲突。使用CCD_ 3得到了相同的结果。

有什么办法让它发挥作用吗?

我也遇到了同样的问题。我在另一个进程中运行了一个DLL,并单独编译了一个控制器应用程序。我的find()和find_or_construct()会挂起,使它看起来像一个死锁。更改为null_mutex_family没有任何作用。

问题是用于编译DLL的字符类型与控制器应用程序的字符类型不同。将两者都设置为使用多字节字符为我修复了它(使用MSVC)。

在访问managed_shared_memory实例之前,我在代码中添加了这一行,这样它就再也不会像那样咬我了。

if (sizeof(char) != 2) throw std::exception("Set your chars right");

如果你试图从一个使用另一种类型的应用程序中找到一个使用一种类型字符构建的对象,boost将陷入一个无休止的循环(我没有耐心尝试找到)。

我在Windows上遇到了同样的问题,在VS2019中使用vc142工具集进行编译。我用了1.73的助推,但我认为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!

之后,我可以通过共享mem段让我的32位进程与64位进程进行对话(反之亦然)。

附言:另外,请记住,32位平台限制了您可以访问的内存量。根据经验,对于Windows 32位进程,您不能获得超过2GB的共享内存(不过我对1.5GB没有问题,但这取决于许多其他因素)。这意味着,如果您决定在64位进程上分配2GB或更多(这很容易实现),那么32位进程上的段构造函数将获得异常,因为boost(通过Win32 API)将拒绝映射那么大的内存块。