2012-10-03 7 views
8

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

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

std::atomic<std::thread::id>は最初に法的な構成ですか?

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

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

答えて

10

std::atomic<std::thread::id>は合法です: std::thread::idは、普通のコピー可能(30.3.1.1p2)で、std::atomic<>(29.5p1)の要件を満たしている必要があります。

しかし、これは不透明なクラスなので、等しいと等しいオブジェクトのビットパターンが同一である必要はありません。

したがって、compare_exchange_weakまたはcompare_exchange_strongを使用すると、同等の値の場合に失敗する可能性があります。

したがって、アドバイスは、前の反復の結果としてexpected値を残すループ内compare_exchange_weakを使用することです。

あなたのループから解釈するセマンティクスは次のとおりです。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(); 

それはないstd::thread::id()である場合、すなわちのみno_id値を変更します。

+0

ありがとうございます。選択的に 'no_id'をリセットするのはいいトリックです、なぜ私はそれが見えなかったのか疑問に思っています:) – vpozdyayev

+0

しかし、おそらく" no_id!= std :: thread :: id() " ループの中。 – cmeerw

+0

@cmeerwはい---私はvpozdyayevのループをできるだけ近く複製しようとしていました。 'compare_exchange_weak'が"間違って "失敗した場合、ほとんどの場合、待機せずにただちにループしたいと思っています。 –

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(); 
    } 
} 
+0

私はループ内で 'compare_exchange_weak'を使用しています。悲しいことに、それは役に立ちません。ところで、ここでの問題は、パディングではなく初期化されていないフィールドです(あなたのリンクの「関連するが分離可能な問題」として言及されています)。私はmemcmpの意味とcompare_exchange_weakについての注意29.6.5/26を知っていますが、 'current'と' expected'がビットごとに異なる表現'演算子==')の値です。 – vpozdyayev

+0

コードサンプルを質問に追加しました。 – vpozdyayev

関連する問題