2013-04-16 4 views
7

http://en.cppreference.com/w/cpp/atomic/atomic_compare_exchangeでは、次のコード例は、std::atomic_compare_exchange_weakの使用例として提示されていますcppreferenceのatomic_compare_exchange_weakのサンプルコードは正しいですか?

void append(list* s, node* n) 
{ 
    node* head; 
    do { 
     head = s->head; 
     n->next = head; 
    } while(! std::atomic_compare_exchange_weak(s->head, head, n)); 
} 

私の理解では、これは私が求められると考えていることs->headを比較することですhead、と*(s->head)を比較する効果を有することですheadである。この例のstd::atomic_compare_exchange_weakの最初の引数は&(s->head)か、何か不足していますか?

UPDATE:std::atomic_compare_exchange_weakの仕様は言う:

bool atomic_compare_exchange_weak(volatile A* object, C * expected, C desired) noexcept; 
bool atomic_compare_exchange_weak(A* object, C * expected, C desired) noexcept; 

効果:アトミックに、メモリ の内容を比較対象で指さ...予想におけるそれと平等のために...

私は*objectexpectedと比較したことを意味するためにこれを取ったが、更なる研究が実際の意味ことを示唆しています「expected」は「expectedで示されている」を意味する)と比較して、*object*expectedと比較される。これは、私の元の質問への答えが "いいえ、s->headのアドレスをcppreferenceのサンプルコードで取る必要はない"という意味です。しかし、objectstd::atomic<T>を指し、予想される必要があるのはTであるという事実は、コンパイルするためにcppreferenceでコードを修正する方法を理解することが難しくなります。リストの先頭とリストの先頭のコピーを比較したいが、リストの先頭がstd::atomic<T>*の場合はstd::atomic_compare_exchange_weakの呼び出しをコンパイルする場合はコピーはT*でなければならず、 reinterpret_castなしでT*std::atomic<T>*を割り当てる方法が見つかりません。その場合でも、std::atomic_compare_exchange_weakの3番目のパラメータはTのタイプである必要がありますが、cppreferenceの例では、2番目と3番目のパラメータが同じタイプであることが示されています。これは、cppreferenceの例が壊れていることを私に示唆しています。私はそれを修正しようとしましたが、私はreinterpret_castを使用する必要性に悩まされました。

興味深いことに、このようなことを理解しようとした私は、msdn page for std::atomic_compare_exchange_weakをチェックアウトしました。そのページには、std::atomic_compare_exchange_*strong*のプロトタイプが表示されています。

誰かがstd::atomic_compare_exchange_weakを使用して単一リンクリストの先頭にノードを挿入するというもっともらしいコードを投稿できますか? ABAの問題を心配する必要はありません。私はちょうどコンパイルする骨格コードを見たいと思う。

+1

'node'はアトミックオブジェクトであると考えられますか? – 0x499602D2

+0

これはcppreferenceの完全なコードスニペットですが、私の質問に対する答えには影響しないと思います。 – KnowItAllWannabe

+2

コードはナンセンスです。 'atomic_compare_exchange_weak'の最初の引数は、アトミック型のオブジェクトへのポインタでなければなりません。 2番目の引数は、対応する値型のオブジェクトへのポインタでなければなりません。 3番目の引数は、対応する値型のオブジェクト(ポインタではありません)です。 –

答えて

1

正しい例は次のようになります。

struct list { 
    std::atomic<node*> head; 
}; 

... 

void append(list* s, node* n) 
{ 
    node* head; 
    do { 
     head = s->head; 
     n->next = head; 
    } while (!std::atomic_compare_exchange_weak(&(s->head), &head, n)); 
    // or while (!s->head.compare_exchange_weak(head, n)); 
} 

あなたは未定義の動作に対処するのでない限りlist::headは、std::atomic対象とする必要があるだろう。問題のプラットフォームでは、ロックを使用してstd::atomicものの一部またはすべてを実装する必要があります。したがって、std::atomic<T*>に追加のメンバーが含まれている可能性があります。reinterpret_cast<std::atomic<T*>*>は、UBがプログラムがクラッシュすることを意味します。

+0

適切なスケルトンが構築されると、コンパイルされます。 [コンパイル可能な例](http://ideone.com/eZnylZ)はIDEOneで入手できます。サンプルコードをテストしていないことを確認しましたが、少なくともそれはコンパイルされています。 – KnowItAllWannabe

関連する問題