我有两个线程,生产者和消费者。数据交换由 std::atomics 内的两个指针控制:
std::atomic<TNode*> next = nullptr;
std::atomic<TNode*> waiting = nullptr;
线程生产者发布准备好的数据,然后检查等待的值:
TNode* newNext = new TNode( );
// ... fill *newNext ...
next.store( newNext, std::memory_order_release );
TNode* oldWaiting = waiting.load( std::memory_order_seq_cst );
if( oldWaiting == nullptr )
{
/* wake up Consumer */
}
waiting
至关重要的是,在 store on 之后加载 onnext
,但std::memory_order_seq_cst
它的保证比我真正需要的要强得多,因为我真的只需要固定这两个访问的顺序。是否可以在不需要的情况下获得我需要的内存顺序memory_order_seq_cst
?
这是图片的其余部分:
线程消费者检查next
。如果它发现它是空的,它waiting
会在阻塞自己之前向 Producer 发出信号。
TNode* newCurrent = next.load( std::memory_order_consume );
if( newCurrent == nullptr )
{
waiting.store( current, std::memory_order_relaxed );
/* wait, blocking, for next != nullptr */
}
current = newCurrent;
整个事情是一个生产者 - 消费者队列,无需所有复杂的机制即可保持低锁定需求。next
实际上是在单链表的当前节点内。数据通常是突发的,因此在大多数情况下,消费者会发现一大堆节点可供消费;除了极少数情况外,两个线程都只在突发之间经历一次锁定和阻塞/唤醒。