Boost、共享内存和向量
Posted
技术标签:
【中文标题】Boost、共享内存和向量【英文标题】:Boost, Shared Memory and Vectors 【发布时间】:2009-04-23 21:34:25 【问题描述】:我需要在进程之间共享一堆字符串(将来可能会更复杂的对象)。我决定使用 boost::interprocess 但我无法让它工作。我确定这是因为我不理解某些东西。我按照他们的示例进行操作,但是如果有使用该库经验的人可以查看我的代码并告诉我出了什么问题,我将不胜感激。问题是它似乎可以工作,但经过几次迭代后,我在阅读器进程和有时在编写器进程上都遇到了各种异常。这是我的实现的简化版本:
using namespace boost::interprocess;
class SharedMemoryWrapper
public:
SharedMemoryWrapper(const std::string & name, bool server) :
m_name(name),
m_server(server)
if (server)
named_mutex::remove("named_mutex");
shared_memory_object::remove(m_name.c_str());
m_segment = new managed_shared_memory (create_only,name.c_str(),65536);
m_stackAllocator = new StringStackAllocator(m_segment->get_segment_manager());
m_stack = m_segment->construct<StringStack>("MyStack")(*m_stackAllocator);
else
m_segment = new managed_shared_memory(open_only ,name.c_str());
m_stack = m_segment->find<StringStack>("MyStack").first;
m_mutex = new named_mutex(open_or_create, "named_mutex");
~SharedMemoryWrapper()
if (m_server)
named_mutex::remove("named_mutex");
m_segment->destroy<StringStack>("MyStack");
delete m_stackAllocator;
shared_memory_object::remove(m_name.c_str());
delete m_mutex;
delete m_segment;
void push(const std::string & in)
scoped_lock<named_mutex> lock(*m_mutex);
boost::interprocess::string inStr(in.c_str());
m_stack->push_back(inStr);
std::string pop()
scoped_lock<named_mutex> lock(*m_mutex);
std::string result = "";
if (m_stack->size() > 0)
result = std::string(m_stack->begin()->c_str());
m_stack->erase(m_stack->begin());
return result;
private:
typedef boost::interprocess::allocator<boost::interprocess::string, boost::interprocess::managed_shared_memory::segment_manager> StringStackAllocator;
typedef boost::interprocess::vector<boost::interprocess::string, StringStackAllocator> StringStack;
bool m_server;
std::string m_name;
boost::interprocess::managed_shared_memory * m_segment;
StringStackAllocator * m_stackAllocator;
StringStack * m_stack;
boost::interprocess::named_mutex * m_mutex;
;
EDIT 编辑为使用 named_mutex。原始代码使用了不正确的 interprocess_mutex,但这不是问题。
EDIT2 我还应该指出,事情发展到一定程度。 writer 进程可以在 reader 中断之前推送几个小字符串(或一个非常大的字符串)。阅读器以 m_stack->begin() 行不引用有效字符串的方式中断。是垃圾。然后进一步执行抛出异常。
EDIT3 我已经修改了类以使用 boost::interprocess::string 而不是 std::string。阅读器仍然失败,内存地址无效。这是读者/作者
//reader process
SharedMemoryWrapper mem("MyMemory", true);
std::string myString;
int x = 5;
do
myString = mem.pop();
if (myString != "")
std::cout << myString << std::endl;
while (1); //while (myString != "");
//writer
SharedMemoryWrapper mem("MyMemory", false);
for (int i = 0; i < 1000000000; i++)
std::stringstream ss;
ss << i; //causes failure after few thousand iterations
//ss << "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" << i; //causes immediate failure
mem.push(ss.str());
return 0;
【问题讨论】:
我对之前的海报感到非常抱歉。我错误地点击了“删除”并删除了我原来发布的这个完全相同的问题。 不能取消删除吗?还是只对答案有效? 我可以对你的内联方法的大小作呕吗?或者这是否标志着我是 C++ 菜鸟? 它们被内联到声明中,但不一定是“内联”。这由编译器决定,或者“内联”关键字。 【参考方案1】:关于您的实施,有几件事让我大吃一惊。一种是使用指向命名互斥对象的指针,而大多数 boost 库的文档倾向于向后弯曲而不使用指针。这导致我要求参考您在构建自己的测试用例时使用的程序 sn-p,因为我也遇到过类似的不幸事件,有时唯一的出路是回到示例并向前迈出一步直到我遇到重大变化。
另一件似乎有问题的事情是您为共享内存分配了一个 65k 块,然后在您的测试代码中,循环到 1000000000,每次迭代都将一个字符串推入您的堆栈。
现代 PC 能够每微秒执行 1000 条甚至更多指令,而 Windows 等操作系统仍在 15 毫秒内分配执行量。块,溢出该堆栈不会花费很长时间。这将是我第一次猜测为什么事情会变得混乱。
附: 我刚从把我的名字改成与我的真实身份相似的东西回来。然后具有讽刺意味的是,我对您问题的回答一直在浏览器页面的左上角盯着我们俩! (也就是说,当然,假设我是对的,这在这个行业中经常不是这样。)
【讨论】:
我已经放弃了 boost 共享内存,而是使用了 Poco::SharedMemory,它无需付出太多努力就可以工作。测试代码从未达到那么多迭代。读者也应该从堆栈中弹出东西以释放内存。 那是我无法理解的部分——我没有看到任何特定的地方或方法让一个线程将控制权交给另一个线程——所以我假设你让时间用完了一个,然后另一个,循环赛。由于 Windows 提供了大量的时间,它会在 15 毫秒之前填满缓冲区。 C++ 中的 iostreams 也经常被缓冲,因此只是输出的存在或范围可能会产生误导。检查我的理论的方法是在缓冲区的每一侧放置一个“警戒区”并寻找覆盖。 - 但无论如何,你做出了改变计划的正确选择。【参考方案2】:也许共享内存不是解决您的问题的正确设计。但是我们不知道,因为我们不知道您首先要达到什么目标。
【讨论】:
以上是关于Boost、共享内存和向量的主要内容,如果未能解决你的问题,请参考以下文章
从 Boost InterProcess Shared Memory 中检索共享向量
boost::interprocess 共享内存段函数 find() 如果段已经存在,则在启动时挂起