[解決済み】std::atomicとは一体何ですか?
質問
私は、次のことを理解しています。
std::atomic<>
はアトミックなオブジェクトです。しかし、どこまでがアトミックなのでしょうか?私の理解では、演算はアトミックになり得ます。オブジェクトをアトミックにするというのは、具体的にはどういうことでしょうか?例えば、次のようなコードを2つのスレッドが同時に実行するとします。
a = a + 12;
では、全体の操作(例えば
add_twelve_to(int)
はアトミックですか?それとも変数に加えられた変更はアトミックなのでしょうか(だから
operator=()
)?
解決方法は?
の各インスタンス化および完全な特殊化 std::atomic<> は、異なるスレッドが未定義の動作を起こすことなく、同時に操作できる型(のインスタンス)を表します。
<ブロッククオートアトム型のオブジェクトは、データ競合のない唯一のC++オブジェクトです。つまり、あるスレッドがアトム型オブジェクトに書き込みを行い、別のスレッドがそれを読み取る場合、その動作は適切に定義されます。
さらに、アトミックオブジェクトへのアクセスは、スレッド間同期を確立し、非アトミックメモリアクセスの順序を、以下のように指定することができます。
std::memory_order
.
std::atomic<>
は、C++ 11 以前の時代には (例えば) を使って実行しなければならなかった操作をラップします。
連動関数
をMSVCで使用したり
アトミックバルタン
GCCの場合
また
std::atomic<>
を使用すると、より多くの制御が可能になります。
メモリオーダー
同期と順序の制約を指定します。C++ 11のアトミックとメモリモデルについてもっと知りたい場合は、以下のリンクが役に立つかもしれません。
- C++アトミックとメモリ順序
- 比較する。C++ 11 のアトミックによるロックレスプログラミングとミューテックスおよび RW ロックの比較
- C++11では、標準化されたメモリモデルが導入されました。これは何を意味するのでしょうか?そして、C++プログラミングにどのような影響を与えるのでしょうか?
- C++11における並行処理
なお、典型的なユースケースでは、おそらく オーバーロードされた算術演算子 または 別のセット :
std::atomic<long> value(0);
value++; //This is an atomic op
value += 5; //And so is this
演算子の構文ではメモリの順番を指定できないため、これらの操作は
std::memory_order_seq_cst
これは、C++ 11 のすべてのアトミック操作のデフォルトの順序だからです。これは、すべてのアトミック操作の間の順次一貫性(グローバルな全順序)を保証するものです。
しかし、場合によっては、これが必要ないこともある(タダで手に入るものはない)ので、より明示的な形式を使用するのもよいでしょう。
std::atomic<long> value {0};
value.fetch_add(1, std::memory_order_relaxed); // Atomic, but there are no synchronization or ordering constraints
value.fetch_add(5, std::memory_order_release); // Atomic, performs 'release' operation
さて、あなたの例です。
a = a + 12;
は、単一のアトミックなオペとして評価されません。
a.load()
(これはアトミックである)、そしてこの値との間の加算は
12
と
a.store()
(これも原子)の最終結果です。先ほども書いたように
std::memory_order_seq_cst
が使われます。
ただし
a += 12
とほぼ等価であり、アトミックな操作になります(先に述べたとおり)。
a.fetch_add(12, std::memory_order_seq_cst)
.
コメントについてですが
通常の
int
はアトミックなロードとストアを持ちます。でラップする意味は何でしょう?atomic<>
?
あなたの発言は、ストアやロードのアトミック性を保証するアーキテクチャにのみ当てはまります。そうでないアーキテクチャもあります。また、アトミックであるためには、通常、ワード/ワードアラインされたアドレスに対して演算が行われる必要があります。
std::atomic<>
はアトミックであることが保証されているもので
あらゆる
プラットフォームで、追加の要件なしに しかも、こんなコードも書けるようになる。
void* sharedData = nullptr;
std::atomic<int> ready_flag = 0;
// Thread 1
void produce()
{
sharedData = generateData();
ready_flag.store(1, std::memory_order_release);
}
// Thread 2
void consume()
{
while (ready_flag.load(std::memory_order_acquire) == 0)
{
std::this_thread::yield();
}
assert(sharedData != nullptr); // will never trigger
processData(sharedData);
}
アサーション条件は常に真である (つまり、決してトリガーされない) ことに注意してください。
while
ループが終了します。それは、以下の理由からです。
-
store()
の後にフラグを実行します。sharedData
が設定されている(と仮定しているgenerateData()
は常に有用なものを返し、特にNULL
) を使用しstd::memory_order_release
の順番になります。
memory_order_release
このメモリ順序でのストア操作では、次のようになります。 リリース 操作: 現在のスレッドでの読み書きの順序を変更することはできません。 後 このストア 現在のスレッドにおけるすべての書き込みは、次のスレッドで見ることができます。 同じアトム変数を取得する他のスレッド
-
sharedData
の後に使用されます。while
ループが終了した後、つまりload()
フラグが0以外の値を返すようになります。load()
が使用します。std::memory_order_acquire
の順番になります。
std::memory_order_acquire
このメモリ順序でのロードオペレーションは、次のように実行されます。 取得 操作 の読み書きができません。 スレッドの順序を変更することができます 以前 このロードを 他のスレッドでのすべての書き込み 同じアトム変数を解放している現在の スレッド .
これにより、同期の正確な制御が可能になり、コードがどのように動作するか/しないか/するつもりか/しないかを明示的に指定することができるようになります。もし、アトミック性だけを保証するのであれば、これは不可能でしょう。特に、以下のような非常に興味深い同期モデルに関しては、このようになります。 リリースコンシューマーオーダー .
関連
-
[解決済み】VC++の致命的なエラーLNK1168:書き込みのためにfilename.exeを開くことができません。
-
[解決済み] 配列のベクトルを扱う正しい方法
-
[解決済み] explicit キーワードの意味は?
-
[解決済み] using namespace std;」はなぜバッドプラクティスだと言われるのですか?
-
[解決済み] C++11では、標準化されたメモリモデルが導入されました。その意味するところは?そして、C++プログラミングにどのような影響を与えるのでしょうか?
-
[解決済み] スマートポインターとは何ですか?
-
[解決済み] ムーブセマンティクスとは何ですか?
-
[解決済み] アトミック属性と非アトミック属性の違いは何ですか?
-
[解決済み】C/C++の"-->"演算子とは何ですか?
-
[解決済み】C++11のラムダ式って何?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】Visual Studio 2015で「非標準の構文。'&'を使用してメンバーへのポインターを作成します」エラー
-
[解決済み】C++でユーザー入力を待つ【重複あり
-
[解決済み】C++のGetlineの問題(オーバーロードされた関数 "getline "のインスタンスがない
-
[解決済み】C++コンパイルタイムエラー:数値定数の前に期待される識別子
-
[解決済み】「corrupted size vs. prev_size」glibc エラーを理解する。
-
[解決済み】クラスのコンストラクタへの未定義参照、.cppファイルの修正も含む
-
[解決済み】システムが指定されたファイルを見つけられませんでした。
-
[解決済み] x86アセンブリの「ロック」命令の意味を教えてください。
-
[解決済み] C++11では、標準化されたメモリモデルが導入されました。その意味するところは?そして、C++プログラミングにどのような影響を与えるのでしょうか?
-
[解決済み】マルチコアアセンブラとはどのようなものですか?