【问题标题】:Create a shared-memory vector of strings创建字符串的共享内存向量
【发布时间】:2012-10-10 10:47:39
【问题描述】:

我正在尝试创建一个类来管理 (std) 字符串的共享内存向量。

typedef boost::interprocess::allocator<std::string, boost::interprocess::managed_shared_memory::segment_manager> shmem_allocator;
typedef boost::interprocess::vector<std::string, shmem_allocator> shmem_vector;

shmem_mgr::shmem_mgr() :
    shmem_(create_only, SHMEM_KEY, SHMEM_SIZE),
    allocator_(shmem_.get_segment_manager())
{
    mutex_  = shmem_.find_or_construct<interprocess_mutex>(SHMEM_MUTEX)();
    condition_ = shmem_.find_or_construct<interprocess_condition>(SHMEM_CONDITION)();
    //buffer_ is of type shmem_vector
    buffer_  = shmem_.construct<shmem_vector>(SHMEM_BUFFER_KEY)(allocator_);
}

void shmem_mgr::run() {
    running_ = true;

    while(running_) {
        scoped_lock<interprocess_mutex> lock ( *mutex_ );

        int size = buffer_->size();

        log_.debug() << size << " queued request(s) found" << std::endl; //LINE 27
        for(int i=0; i<size; i++) {
            log_.debug() << buffer_->at(i); // at() crashes my app
        }

        buffer_->clear(); //so does clear()
        condition_->wait (lock);
    }
}

客户端成功将一个字符串添加到向量中(它也成功从缓冲区中读取该字符串进行调试),管理器(上面的代码)接收到信号(条件变量),写入向量中有一个字符串(第 27 行),但是当它尝试通过 at() 获取该字符串时,应用程序崩溃了。


编辑:我发现,std::string 的使用是不可能的,boost ipc 中有一个 string 容器仅用于这种情况。这并没有改变我需要一个 (boost/std) 字符串向量的事实......

我如何在共享内存中传递字符串?我需要将它们存储在 shmem 中的某个缓冲区(一次能够存储 >1 个)中,并且然后在第二个过程中获取 - 这就是要求。输入总是std::string,输出也是,但在shmem中的内部表示可能不同。

【问题讨论】:

  • 在哪里声明了“i”?你不是要使用它吗?
  • 不,只是一个愚蠢的错字。固定。
  • @elmes:还是错了,你将迭代器传递给at(),但at() 只需要std::vector&lt;T&gt;::size_type。即使该代码可以编译(它不会),它也没有任何意义。同样奇怪的是,log.debug() 返回了一个本来应该以这种方式使用的左值……你为什么要传递一个参数?
  • 1.它必须是向量吗? 2. 共享内存是否需要保存字符串或者是否足以保存指向字符串的指针? 3. 你需要并发访问吗(我假设不是因为你使用互斥锁)? 4. 代码需要跨平台吗?您现在可能知道标准迭代器不是线程安全的。如果您能回答以上问题,我可以提供解决方案。
  • 1.不一定,但随机访问是的。 2. 我有一个用例,输入时我有std::string,输出时需要std::string(第二个进程) 3. 我不能禁止并发使用。互斥是用于条件的,条件是不浪费cpu时间(而是等待消费者进程中的另一个输入) 4.是的!

标签: c++ boost shared-memory boost-interprocess


【解决方案1】:

来自docs

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/allocators/allocator.hpp>

int main ()
{
   using namespace boost::interprocess;
   //Typedefs
   typedef allocator<char, managed_shared_memory::segment_manager>
      CharAllocator;
   typedef basic_string<char, std::char_traits<char>, CharAllocator>
      MyShmString;
   typedef allocator<MyShmString, managed_shared_memory::segment_manager>
      StringAllocator;
   typedef vector<MyShmString, StringAllocator>
      MyShmStringVector;

   //Open shared memory
   //Remove shared memory on construction and destruction
   struct shm_remove
   {
      shm_remove() { shared_memory_object::remove("MySharedMemory"); }
      ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); }
   } remover;

   managed_shared_memory shm(create_only, "MySharedMemory", 10000);

   //Create allocators
   CharAllocator     charallocator  (shm.get_segment_manager());
   StringAllocator   stringallocator(shm.get_segment_manager());

   //This string is in only in this process (the pointer pointing to the
   //buffer that will hold the text is not in shared memory).
   //But the buffer that will hold "this is my text" is allocated from
   //shared memory
   MyShmString mystring(charallocator);
   mystring = "this is my text";

   //This vector is only in this process (the pointer pointing to the
   //buffer that will hold the MyShmString-s is not in shared memory).
   //But the buffer that will hold 10 MyShmString-s is allocated from
   //shared memory using StringAllocator. Since strings use a shared
   //memory allocator (CharAllocator) the 10 buffers that hold
   //"this is my text" text are also in shared memory.
   MyShmStringVector myvector(stringallocator);
   myvector.insert(myvector.begin(), 10, mystring);

   //This vector is fully constructed in shared memory. All pointers
   //buffers are constructed in the same shared memory segment
   //This vector can be safely accessed from other processes.
   MyShmStringVector *myshmvector =
      shm.construct<MyShmStringVector>("myshmvector")(stringallocator);
   myshmvector->insert(myshmvector->begin(), 10, mystring);

   //Destroy vector. This will free all strings that the vector contains
   shm.destroy_ptr(myshmvector);
   return 0;
}

【讨论】:

  • 几乎完美。只需描述如何将MyShmString 转换为std::string
  • std::string s = std::string(myShmString.begin(), myShmString.end());
【解决方案2】:

您需要为您的可共享 stl 类定制一个分配器。您需要在分配器中定义一个基于自身的指针(ACE 和 boost 有这些)。在相对的两侧,(CONTIGUOUS)共享内存通常位于不同的地址。您还需要一个共享内存分配子系统(堆管理器)(分配器从中分配) - 所有非平凡的低级代码,但绝对是可行的,一旦你拥有它,它就可以在任何地方使用。如果你做了所有这些,你只需要传递非平面结构的位移(从(CONTIGUOUS!!)堆区域的开头)。

您可以创建队列以及您可能想要的所有其他内容 - 前提是对象中的“指针”是基于自身的,并且非平面部分中的不连续部分来自一个大的连续部分。

您不能使用 std::string,因为除非您控制分配,否则标准字符串中的内存与您的共享内存无关 - 与任何其他 stl 结构相同

也必须(像往常一样)解决/同意所有权问题

【讨论】:

  • 好的。 boost::interproces::vectorboost::interprocess::string 或某些字符串的任何其他向量怎么样?我需要跨 2 个进程传输一些字符串,我该怎么办
【解决方案3】:

您可以使用 boost::interprocess::managed_shared_memory。以下程序在 2 个进程之间传递 boost::interprocess::string。在我的机器(Ubuntu Linux)上运行良好。 您可以使用 managed_shared_memory 传递向量或对象。 boost::interprocess::string 有一个 c_str() 方法。

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <cstring>
#include <cstdlib>
#include <string>
#include <iostream>

int main(int argc, char *argv[])
{
  using namespace boost::interprocess;
  typedef boost::interprocess::allocator<char, boost::interprocess::managed_shared_memory::segment_manager> CharAllocator;
  typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> string;
  if(argc == 1){  //Parent process

      boost::interprocess::shared_memory_object::remove("MySharedMemory");

      //Create a shared memory object.
      managed_shared_memory shm (create_only, "MySharedMemory", 1024);

      string *s = shm.find_or_construct<string>("String")("Hello!", shm.get_segment_manager());
      std::cout << *s << std::endl;

      //Launch child process
      std::string s1(argv[0]); s1 += " child ";
      if(0 != std::system(s1.c_str()))
         return 1;
  }
  else{
      //Open already created shared memory object.
      managed_shared_memory shm (open_only, "MySharedMemory");
      std::pair<string *,std::size_t> ret = shm.find<string>("String");
      std::cout << *(ret.first) << std::endl;
  }
  return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-06
    • 2014-04-27
    • 1970-01-01
    • 1970-01-01
    • 2015-10-29
    • 1970-01-01
    相关资源
    最近更新 更多