Producer と Consumer の 2 つのスレッドがあります。データ交換は、std::atomics 内の 2 つのポインターによって制御されます。
std::atomic<TNode*> next = nullptr;
std::atomic<TNode*> waiting = nullptr;
スレッド プロデューサーは、準備されたデータを公開し、その後、waiting の値をチェックします。
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 */
}
load on が store on の後に来ることは非常に重要ですが、waiting
next
実際にstd::memory_order_seq_cst
はこれら 2 つのアクセスの順序を修正するだけでよいので、必要以上に強力な保証があります。を必要とせずに必要なメモリ順序を取得することは可能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
実際には、単方向リストの現在のノード内にあります。通常、データはバーストで送信されるため、ほとんどの場合、Consumer は消費の準備が整ったノードを多数見つけます。まれなケースを除いて、両方のスレッドがロックとブロッキング/ウェイクアップをバースト間で 1 回だけ実行します。