8

標準では、「thread :: id型のオブジェクトは、実行のスレッドを表さないすべてのスレッドオブジェクトに単一の個別の値を提供します」と述べています。それは、に関するoperator==単一/個別の値ですか、それとも実際のビット単位の単一/個別の値ですか?

質問の理由:MSVC2012std::thread::id::id()は、そのフィールドの1つにガベージを残し、std::atomic<std::thread::id>(ビット単位の比較に依存するため)で比較交換を行うコードを壊します。

std::atomic<std::thread::id>そもそも法的な構成ですか?

編集:参考のために、コードは次のようになります:

while( !worker_id.compare_exchange_weak( no_id = thread_id_type(), self_id ) )
    sleep();
4

2 に答える 2

11

まず、std::atomic<std::thread::id>合法です。(29.5p1)std::thread::idの要件を満たす、簡単にコピー可能(30.3.1.1p2)である必要がありますstd::atomic<>

ただし、これは不透明なクラスであるため、同等に比較されるオブジェクトのビットパターンが同一である必要はありません。

したがって、compare_exchange_weakまたはを使用compare_exchange_strongすると、等しい値を比較すると失敗する可能性があります。

したがって、前の反復の結果として値を残してcompare_exchange_weak、ループで使用することをお勧めします。expected

worker_idあなたの場合、私があなたのループから解釈するセマンティクスは次のとおりです。別のスレッドのIDである間、または交換worker_idstd::thread::id失敗した間、ループを続けます。これは、次の方法で実現できます。

no_id=std::thread::id();
while((no_id!=std::thread::id()) ||
      !worker_id.compare_exchange_weak( no_id, self_id ) ){
    if(no_id!=std::thread::id()) no_id=std::thread::id();
    sleep();
}

また

no_id=std::thread::id();
while(!worker_id.compare_exchange_weak(
          (no_id!=std::thread::id())?(no_id=std::thread::id())?no_id, self_id ) )
    sleep();

つまり、値が変更されていないno_id場合にのみ値を変更します。 std::thread::id()

于 2012-10-03T10:37:27.927 に答える
5

これはLWG924で議論されました。基本的には使用できませんがcompare_exchange_strong、compare_exchange_weakをループで使用できるはずです。

expected = current.load();
do {
  desired = function(expected);
} while (!current.compare_exchange_weak(expected, desired));

編集:無条件に値をリセットすると、ループの目的が無効になります-提供されたコードに基づいて、最善の解決策は次のようになります:

no_id = std::thread::id();
while( !worker_id.compare_exchange_weak( no_id, self_id ) )
{
  if (no_id != std::thread::id())
  {
    sleep();
    no_id = std::thread::id();
  }
}
于 2012-10-03T08:42:46.340 に答える