提升 IPC 字符串长度段错误

boost IPC string length segfault?

本文关键字:错误 段错误 IPC 字符串 提升      更新时间:2023-10-16

我有一个非常小的两个程序的例子,一个用于编写共享内存段,另一个用于从中读取。我意识到std::string(和其他容器)可能存在问题,因此尝试了boost::interprocess::string这是一个boost::containers::string。 我很确定这缺少一些真正基本和简单的东西,但看不到它!

无论如何,概要是,当字符串很小(我认为虽然比 SSO 大)时,运行第一个程序会写入内存,第二个程序读取得很好。但是,如果我像这里的例子一样使字符串非常大,那么读取程序就会出现段错误。如果读取和写入都在同一个过程中,但功能不同,我就成功了(因此除了通过 ipc 之外不共享任何数据。下面的代码writeipc.cc

#include <boost/interprocess/managed_shared_memory.hpp> 
#include <boost/interprocess/containers/string.hpp>
#include <iostream> 
#include <utility> 
int main() 
{
  typedef boost::interprocess::string bi_string;
  boost::interprocess::shared_memory_object::remove("Test"); 
  boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::create_only, "Test", 65536); 

  bi_string* i = managed_shm.construct<bi_string>("string")("abcdefghijklmnopqrstuvwxyzaskl;dfjaskldfjasldfjasdl;fkjwrotijuergonmdlkfsvmljjjjjjjjjjjjjj");  // make smaller (ie "jjjjjjjjjjjjjj" and test passes 
  std::cout << "inserting into shm" << *i << std::endl; 
  std::pair<bi_string*, size_t> q = managed_shm.find<bi_string>("string"); 
  std::cout << *q.first << std::endl;
 while(true)
    std::cout << "still running"; // hack to keep process running (not required)
}

readipc.cc

#include <boost/interprocess/managed_shared_memory.hpp> 
#include <boost/interprocess/containers/string.hpp>
#include <iostream> 
int main() 
{
  typedef boost::interprocess::string bi_string;
  boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_only, "Test"); 
  std::pair<bi_string*, std::size_t> p = managed_shm.find<bi_string>("string"); 
  std::cout << "existing value" << *p.first << std::endl; 
}

好的,答案与分配器有关。

我正在发布我认为是答案的内容,以便其他人快速了解如何开始使用IPC。我发现许多关于网络的例子不能很好地解释这个过程,给人的印象是使用普通字符串等就可以了,直到你从不同的过程中阅读。因此,要完全实施解决方案,需要一些额外的小步骤。

实质上,您不能使用普通 stl 类型容器提供的分配器。此处记录了此文档

这是在哪里分配的?

Boost.进程间容器放置在共享内存/内存中 映射文件等...同时使用两种机制:

Boost.Interprocess construct<>, find_or_construct<>... functions. These functions place a C++ object in the shared memory/memory mapped

文件。但这只放置了对象,而不是内存 对象可以动态分配。 共享内存分配器。这些允许分配共享内存/内存映射文件部分,以便容器可以分配 用于存储新插入元素的动态内存片段。

这意味着要放置任何 Boost.Interprocess 容器(包括 Boost.Interprocess strings)在共享内存或内存映射文件中, 容器必须:

Define their template allocator parameter to a Boost.Interprocess allocator.
Every container constructor must take the Boost.Interprocess allocator as parameter.
You must use construct<>/find_or_construct<>... functions to place the container in the managed memory.

如果您执行了前两点,但没有使用构造<>或 find_or_construct<>创建仅放置在 进程,但为共享的包含类型分配内存 内存/内存映射文件。

我创建了几个示例函数,可以在这里找到

上面缺少的是

namespace bi = boost::interprocess;
typedef bi::allocator<char, bi::managed_shared_memory::segment_manager> CharAllocator;
typedef bi::basic_string<char, std::char_traits<char>, CharAllocator> bi_string;

现在这是一个字符串,当我们可以为它获取分配器时可以存储它。这意味着像这样从内存段获取分配器

  bi::managed_shared_memory segment(bi::create_only, "shm name",
                                                     65536);
  // Create an object of Type initialized to type
  CharAllocator charallocator(segment.get_segment_manager());

现在,Charallocator 可用于构造一个字符串类型,该类型将在共享内存位置工作并能够正确读回。字符串的创建方式为:

 bi_string str(charallocator);

然后,您可以为此分配一个字符串。例如std::string test("a test string");

str = test.c_str();

如果你构造一个段,你的字符串将被存储

segment.construct<bi_string>("some name")(str)

您可以在共享内存存储中存储多个段。我希望这对其他人有所帮助。上面的链接中提供了所有代码。