我想使用运行时指定的最大条目数在共享内存中创建一个无锁环缓冲区。我的代码基于我在GitHub中找到的示例。我使用此代码在共享内存中成功创建了一个无锁环缓冲区
在我的例子中,我需要指定环形缓冲区在运行时构造时可以接受的最大条目数,而不是在每个示例的编译时。下面显示了在示例中构造shm::ring_buffer
的调用。
namespace bip = boost::interprocess;
namespace shm
{
using char_alloc = bip::allocator<char, bip::managed_shared_memory::segment_manager>;
using shared_string = bip::basic_string<char, std::char_traits<char>, char_alloc>;
using ring_buffer = boost::lockfree::spsc_queue<shared_string, boost::lockfree::capacity<200>>;
}
共享内存段按如下方式分配:
mQueuingSharedMem = std::make_unique<bip::managed_shared_memory>(
bip::open_or_create, (mSharedMemoryName + "Queuing").c_str(), rSHMSize);
根据GitHub示例,当我通过可选的boost::lockfree::capacity<>
模板参数构造在编译时指定的最大大小的环形缓冲区时,一切正常(注意:共享内存段construct
方法需要[]中的#ring_buffers和构造函数参数在后面的括号中指定。
auto pSharedMemAddr = mQueuingSharedMem->construct<
shm::ring_buffer>(rQueuingPortName.c_str())[1](/*aMaxNumMessages*/);
我认为为了在运行时构造上面的shm :: ring_buffer,我需要从boost::lockfree::capacity<200>
中删除第二个shm::spsc_queue
硬编码大小参数,而是传递{的最大大小{1}}和shm::ring_buffer
的共享内存分配器。我找到了类似的答案here,但我无法使其适应我的代码。
我对上面的代码进行了以下更改,试图在运行时指定环形缓冲区的大小:
shm::shm_string
我得到了大量无法理解的编译器错误,我不太清楚如何修复:
namespace bip = boost::interprocess;
namespace shm
{
using char_alloc = bip::allocator<char, bip::managed_shared_memory::segment_manager>;
using shared_string = bip::basic_string<char, std::char_traits<char>, char_alloc>;
using ring_buffer = boost::lockfree::spsc_queue<shared_string/*, boost::lockfree::capacity<200>*/>;
}
shm::char_alloc char_alloc(mQueuingSharedMem->get_segment_manager());
auto pSharedMemAddr = mQueuingSharedMem->construct<
shm::ring_buffer>(rQueuingPortName.c_str())[1](aMaxNumMessages);
答案 0 :(得分:1)
动态大小仅在您指定进程间内存分配器时才有效:http://www.boost.org/doc/libs/1_65_1/doc/html/boost/lockfree/allocator.html。
可悲的是,虽然spsc_queue
does support有状态分配器:
定义分配器。 boost.lockfree支持有状态分配器,并与Boost.Interprocess分配器兼容
它似乎不支持将分配器传递给它的元素(uses_allocator<>
)所需的shared_string
协议,即使使用scoped_allocator_adaptor
¹也不行。
我之前碰到过这个:
Shared-memory IPC synchronization (lock-free)(使用编译时大小的spsc_queue
)
所以我的建议是删除其中一个成分:
对于后者,您可以将队列存储为manged bip::shared_ptr<shared_string>
而不是:
<强> Live On Coliru 强>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/managed_mapped_file.hpp> // for Coliru
#include <boost/interprocess/smart_ptr/shared_ptr.hpp>
#include <boost/lockfree/spsc_queue.hpp>
#include <iostream>
/// noisy - traces special members
struct noisy {
noisy& operator=(noisy&&) noexcept { std::cout << "operator=(noisy&&)\n"; return *this; }
noisy& operator=(const noisy&) { std::cout << "operator=(const noisy&)\n"; return *this; }
noisy(const noisy&) { std::cout << "noisy(const noisy&)\n"; }
noisy(noisy&&) noexcept { std::cout << "noisy(noisy&&)\n"; }
~noisy() { std::cout << "~noisy()\n"; }
noisy() { std::cout << "noisy()\n"; }
};
namespace bip = boost::interprocess;
namespace blf = boost::lockfree;
namespace Shared {
using Segment = bip::managed_mapped_file; // Coliru unsupported: managed_shared_memory;
using Manager = Segment::segment_manager;
template <typename T> using Alloc = bip::allocator<T, Manager>;
using String = bip::basic_string<char, std::char_traits<char>, Alloc<char> >;
// using Element = String;
// For debug/demonstration
struct Element : String, noisy { using String::String; }; // inherit constructors
using Ptr = bip::managed_shared_ptr<Element, Segment>::type;
using Buffer = blf::spsc_queue<Ptr, blf::allocator<Alloc<Ptr> > >;
}
static std::string unique_id_gen() {
static std::atomic_size_t s_gen { 0 };
return "buffer_element" + std::to_string(++s_gen);
}
int main() {
struct shm_remove {
shm_remove() { bip::shared_memory_object::remove("MySharedMemory"); }
~shm_remove() { bip::shared_memory_object::remove("MySharedMemory"); }
} remover;
Shared::Segment segment(bip::create_only, "MySharedMemory", 4 << 20);
auto& buffer = *segment.construct<Shared::Buffer>(bip::unique_instance)[1](20, segment.get_segment_manager());
auto create = [&segment](auto&&... args) {
return make_managed_shared_ptr(segment.construct<Shared::Element>(unique_id_gen().c_str())
(
std::forward<decltype(args)>(args)...,
segment.get_segment_manager()
), segment);
};
std::cout << "Pushing\n";
for (auto msg : { "hello", "world", "bye", "cruel", "world" })
buffer.push(create(msg));
std::cout << "Popping\n";
{
Shared::Ptr into;
while (buffer.pop(into)) {
std::cout << "Popped: '" << *into << "'\n";
}
std::cout << "Going out of scope\n";
} // RAII
std::cout << "Out of scope\n";
{
// make sure any other owned queue elements are freed if the queue is destroyed before it's empty:
for (auto msg : { "HELLO", "WORLD", "BYE", "CRUEL", "WORLD" })
buffer.push(create(msg));
std::cout << "Destroying buffer containing 5 elements\n";
segment.destroy<Shared::Buffer>(bip::unique_instance);
}
}
打印:
Pushing
noisy()
noisy()
noisy()
noisy()
noisy()
Popping
Popped: 'hello'
~noisy()
Popped: 'world'
~noisy()
Popped: 'bye'
~noisy()
Popped: 'cruel'
~noisy()
Popped: 'world'
Going out of scope
~noisy()
Out of scope
noisy()
noisy()
noisy()
noisy()
noisy()
Destroying buffer containing 5 elements
~noisy()
~noisy()
~noisy()
~noisy()
~noisy()
¹搜索我的答案,了解如何在共享内存中使用其他容器容器