私は、Anthony Williamsの「C++ Concurrency in Action」と、第5章で新しいマルチスレッド対応メモリモデルとアトミック操作について説明しています。
ユーザー定義の
UDT
にstd::atomic<UDT>
を使用するには、このタイプにtrivialコピー割り当て演算子が必要です。
私が理解しているように、これは、以下がtrueを返す場合、std::atomic<UDT>
を使用できることを意味します。
std::is_trivially_copyable<UDT>::value
このロジックにより、std::string
のテンプレート引数としてstd::atomic
を使用できず、正しく機能させることはできません。
ただし、次のコードはコンパイルされ、予想される出力で実行されます。
#include <atomic>
#include <thread>
#include <iostream>
#include <string>
int main()
{
std::atomic<std::string> atomicString;
atomicString.store( "TestString1" );
std::cout << atomicString.load() << std::endl;
atomicString.store( "TestString2" );
std::cout << atomicString.load() << std::endl;
return 0;
}
これは未定義の動作の場合で、たまたま期待どおりに動作しますか?
前もって感謝します!
標準では_std::atomic<std::string>
_の特殊化が指定されていないため、汎用_template <typename T> std::atomic<T>
_が適用されます。 29.5 [atomics.types.generic] p1の状態:
アトミックな汎用クラステンプレートがあります。テンプレート引数Tの型は簡単にコピーできなければならない(3.9)。
実装がこの要件の違反を診断しなければならないという記述はありません。そのため、(a)_std::atomic<std::string>
_を使用すると未定義の動作が呼び出されるか、(b)実装が準拠拡張として_std::atomic<std::string>
_を提供します。
_std::atomic<T>
_( http://msdn.Microsoft.com/en-us/library/vstudio/hh874651.aspx )のMSDNページを見ると、T
は簡単にコピー可能で、_std::atomic<std::string>
_について特定のことは何も言いません。拡張機能の場合、文書化されていません。私のお金は未定義の行動です。
具体的には、17.6.4.8/1が適用されます( 私をまっすぐに設定してくれたDanielKrüglerに感謝します ):
特定の場合(置換関数、ハンドラー関数、標準ライブラリテンプレートコンポーネントのインスタンス化に使用される型の操作)、C++標準ライブラリは、C++プログラムによって提供されるコンポーネントに依存します。これらのコンポーネントが要件を満たしていない場合、標準では実装に要件はありません。
_std::string
_は、テンプレートパラメータT
が簡単にコピー可能であるという_std::atomic<T>
_要件を確実に満たしていないため、標準では実装に要件はありません。実装の品質の問題として、static_assert(std::is_trivially_copyable<T>::value, "std::atomic<T> requires T to be trivially copyable");
はこの違反をキャッチする簡単な診断であることに注意してください。
2016-04-19更新:変更がいつ発生したかわかりませんが、VS2015 Update 2は_std::atomic<std::string>
_を診断します:
エラーC2338:atomicはTを簡単にコピーできる必要があります。
いいえ、これは未定義の動作です。さらに、std :: stringは簡単にコピーできないため、適合コンパイラは「少なくとも1つの診断メッセージ」を発行する必要があります。
29.5原子タイプ
アトミックな汎用クラステンプレートがあります。テンプレート引数Tの型は簡単にコピーできるものでなければなりません(3.9)。
1.4実装コンプライアンス
—プログラムに診断可能なルールの違反が含まれている場合[...]適合実装は、少なくとも1つの診断メッセージを発行します。
std::atomic<std::string>
を読み書きしようとするスレッドが複数ある場合、なぜこれが「正しく」動作すると思いますか?
これはC++です。あなたは間違いなく自分自身を撃つことができます。自由に使用できる要件を満たさないタイプを使用したい場合、コンパイラーは「停止」する可能性があります(そうではありません!)が、複数のスレッドが読み取ろうとすると、奇妙な/説明できない動作が見られるようになります文字列を書き込みます。
この要件は、読み取りと書き込みのアトミック性を保証するためのものです。オブジェクトが簡単にコピーできない場合は、このシーンを視覚化します。文字列には「Old Value」が含まれていました。 1ライターは.store( "New Data")を発行します。同じ変数で.load()を発行する別のスレッドがあり、trivially_copyableプロパティがないため、リーダースレッドは "Nld Value"または "New Value"などを参照できます。アトミックに更新できないため、奇妙な結果になります。
投稿した例はシーケンシャルコードであるため、これは発生しません。