Tho*_*son 2 boost locking thread-safety emplace
常规std::vector具有emplace_back避免不必要的副本。有理由spsc_queue不支持吗?emplace由于某种原因无法使用无锁队列吗?
我不是 boost 库的实现者也不是维护者,所以为什么不包含emplace成员函数背后的基本原理超出了我的知识范围,但如果你真的需要它,自己实现它并不太难。
该spsc_queue具有基类的任一compile_time_sized_ringbuffer或runtime_sized_ringbuffer取决于如果队列的大小在编译或不是已知的。这两个类维护实际使用的缓冲区,但动态缓冲区和编译时缓冲区之间存在明显差异,但在这种情况下,将它们的push成员函数委托给一个公共基类 - ringbuffer_base。
该ringbuffer_base::push功能是比较容易神交:
bool push(T const & t, T * buffer, size_t max_size)
{
const size_t write_index = write_index_.load(memory_order_relaxed); // only written from push thread
const size_t next = next_index(write_index, max_size);
if (next == read_index_.load(memory_order_acquire))
return false; /* ringbuffer is full */
new (buffer + write_index) T(t); // copy-construct
write_index_.store(next, memory_order_release);
return true;
}
Run Code Online (Sandbox Code Playgroud)
下一个项目应该存储的位置的索引是通过relaxed加载完成的(这是安全的,因为此类的预期用途是push调用的单个生产者)并获取适当的下一个索引,检查以确保一切都在- bounds(使用加载获取与调用 的线程进行适当的同步pop),但我们感兴趣的主要语句是:
new (buffer + write_index) T(t); // copy-construct
Run Code Online (Sandbox Code Playgroud)
它在缓冲区中执行放置新副本构造。传递一些用于T直接从可行的构造函数参数构造 a 的参数并没有本质上是线程不安全的。我编写了以下代码段并在整个派生类中进行了必要的更改,以适当地将工作委托给基类:
template<typename ... Args>
std::enable_if_t<std::is_constructible<T,Args...>::value,bool>
emplace( T * buffer, size_t max_size,Args&&... args)
{
const size_t write_index = write_index_.load(memory_order_relaxed); // only written from push thread
const size_t next = next_index(write_index, max_size);
if (next == read_index_.load(memory_order_acquire))
return false; /* ringbuffer is full */
new (buffer + write_index) T(std::forward<Args>(args)...); // emplace
write_index_.store(next, memory_order_release);
return true;
}
Run Code Online (Sandbox Code Playgroud)
也许唯一的区别是确保传入的参数Args...实际上可以用于构造 a T,当然是通过std::forward而不是复制构造来进行放置。