1

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 の後に来ることは非常に重要ですが、waitingnext実際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 回だけ実行します。

4

3 に答える 3