質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

6回答

6721閲覧

ミューテックスとアトミック処理について

strike1217

総合スコア651

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

2グッド

3クリップ

投稿2018/12/24 10:34

編集2018/12/25 03:16

主にアトミック処理に関する質問です。
いくつか不明な点があります。

アトミック処理とミューテックスの違いについて確認しておきます。
mutex と atomic の違いは何か、どちらが良いか
アトミック操作

アトミック操作の長所は、ロックに比べて比較的処理が速く、デッドロックやコンボイなどを回避できる点にあります。 短所は、限られた操作しか行うことができず、より複雑な操作を効率良く総合的に扱うには不十分なことです。

次に、ロックフリーについて・・・
C++ストラウストラップ氏の本の中では以下のようにあります。

ロックフリープログラミングは明示的なロックを使わずに並行プログラムを開発するためのの一連の技法だ。

明示的なロックの代わりに使うのが、小規模オブジェクトに対するデータ競合を防ぐための(ハードウェアが直接サポートする)基礎的な演算である。データ競合が発生しない基礎的な演算は、一般的にアトミック処理と呼ばれる。
・・・
ロックフリー技法を用いると、ロック技法を用いた場合よりも大幅に速度が向上することもある。
標準アトミック型と処理は、従来方式のロックフリーなコードに代わる、可搬性を持った代替手法を提供する。

[疑問1]
アトミック処理とは、ミューテックスと同じように排他的処理を提供するが、ミューテックスとは対照的にロックを使用しない。
つまり、アトミック処理 = ロックフリー 完全に同値なものだと解釈してよろしいのでしょうか?
アトミックとミューテックスを併用したプログラミングスタイルというものも存在するのでしょうか?
また、アトミック処理以外にもロックフリーを実現することは可能なのでしょうか??

[疑問2]
アトミック処理は、ロックを使用しないのに、どうやって排他的制御を実現しているのでしょうか??
自分の予想なのですが・・・これってもしかしてCPUにアトミック専用命令みたいなものが用意されている?・・・のでしょうか? EX : add命令 -> atomic.add命令 みたいな感じですかね。


ここからvolatileが出てきます。

C++ストラウストラップ氏の本から以下抜粋です。

アトミック処理は、メモリ状態が、指定したメモリオーダの要求通りとなることを保証する。

(メモリオーダーとは)コンパイラやオプティマイザはプログラムの実行速度向上を目的に、命令の順序を並べ替えることがある。
・・・ 
もっとも単純なメモリオーダーは、逐次一貫と呼ばれるものだ。逐次一貫メモリモデルでは、すべてのスレッドは、実行されたすべての処理の結果が同じ順序として見える。その順序は、単一スレッドで命令を逐次実行した場合の順序である。
スレッドが命令の実行順序を変更することはあり得るが、他のスレッドが変数を参照する時点では、それまで実行された処理、及び(その結果である)メモリロケーションの値が的確に定義された状態であることが保証されて、全スレッドから同じものが見える。メモリロケーションに一貫した観点を強制した上で値を”見る”ことをアトミック処理と呼ぶ。

ふぅーーーー。ちょっと長いですね。
要は、命令順序は変更されることは、あっても変数内の値は、的確に定義された状態であることが保証されているということですよね。

では、ここで別の書籍のサンプルコードを見てみます。

C++

1volatile std::atomic_flag shared_lock; 2 3void thread_function(int id){ 4 while(shared_lock.test_and_set()) 5 sleep(1); 6 shared_data = id; 7 std::cout << "Thread " << id << " set shared value to " << shared_data << std::endl; 8 usleep(id * 100); 9 std::cout << "Thread " << id << " has shared value as " << shared_data << std::endl; 10 shared_lock.clear(); 11}

ん??
volatileが出てきています。
volatileが必要な場面を見つけ出す

[疑問3]
このvolatileはどのような効果を持っているのでしょうか?
命令順序は変更されることは、あっても変数内の値は、的確に定義された状態であることはアトミックによって保証されているはずですよね。
これって、volatileの効果とかぶっていませんか??

volatile変数は「コンパイラからは検知できない任意タイミングで更新される可能性のある変数」
スレッドには当てはまらない。はずです。
となると、このvolatileは命令の実行順序と関係がありそうですね。

アトミックはvolatileの性質を含んでいるのでしょうか??

[疑問4]
アトミックとは別にvolatileによく似ているのが、メモリフェンス(メモリバリア)の存在です。

CPUやコンパイラは、メモリフェンスを越えて読み込みと書き込みの操作の順序を入れ替えることができない。

volatile宣言がされている場合、コンパイラはそのデータが置かれたメモリに対する読み書きの順序を変更できない。しかし、これらの読み書きと、他のメモリに対する読み書きとの順序を変更してもよい。

ん〜〜??
なんか言っている事が同じ気がするんですが・・・
volatileとメモリバリアの違いがハッキリしません。

アトミック処理は、メモリ状態が指定したメモリオーダーの要求通りとなる事を保証する。

デフォルトのメモリオーダーは、memory_order_seq_cstである。

C++

1int x = 0, y = 0, r1 = 0, r2 = 0; 2 3// スレッド1 4x = 1; 5r1 = y; 6 7// スレッド2 8y = 1; 9r2 = x;

プログラム終了時、r1とr2の値はどちらも0になる可能性がある。この状況が発生するのは、スレッド2が1を代入する前にスレッド1がyを読み込んでしまう場合、もしくはスレッド2はyに1を代入したが、値がキャッシュされ、スレッド1がyを読む際に値が反映されていない場合がある。

メモリバリアはこれらのデータ競合を緩和する低レベルな方法である。
次のコードはメモリフェンスを追加している。

C++

1int x = 0, y = 0, r1 = 0, r2 = 0; 2 3//スレッド1 4x = 1; 5atomic_thread_fence(memory_order_seq_cst); 6r1 = y; 7 8//スレッド2 9y = 1; 10atomic_thread_fence(memory_order_seq_cst); 11r2 = x;

これ、volatileではダメなんでしょうか?

[疑問5]
疑問2と似ているのですが・・・このメモリバリアと呼ばれるものはどうやって実現しているのでしょうか?
これも、CPUにメモリバリア専用命令みたいなのが用意されているのでしょうか?
メモリバリアの atomic_thread_fenceの名前でatomicが付いているので、そうなのかなぁ〜〜という推測です。

疑問3と4は、アトミックとvolatileとメモリバリアの違いについての疑問です。
わかる方お願いします。

環境は、g++ Linux です。

[追記]
疑問3については、volatileが必要な場面を見つけ出すの中でChironianさんが触れていることに非常に近いですね。

なるほど。そう言えば、関数呼び出しを挟めば最適化が抑止されたことがありました。そのように規定されているのですね!(lock()が同期用のロックかどうかコンパイラは把握できない筈ですし)

アトミック変数はどうでしょう? 必要に応じて暗黙的にvolatileになるのでしょうか?

アトミック変数がvolatileの性質を含んでいるような気がしますが・・・
質問中のコードにはなぜvolatileが登場しているんでしょうかね・・・

kazuyakazuya, atata0319👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答6

0

ベストアンサー

[疑問1]
つまり、アトミック処理 = ロックフリー 完全に同値なものだと解釈してよろしいのでしょうか?

違います。用語を混同しています。「アトミック処理」というのは、日本語では「不可分操作」と訳されていますが、要するに別スレッドからの干渉を受けずに一連の処理を実行することを指す用語です。そして、その実現方法の一つがミューテックスによるロック(排他制御)であり、そのようなロックの仕組みを使わずに、つまり、スレッドの「待ち状態」を作らずにCPU命令等のハード的な仕組みでアトミック処理を行うことをロックフリーと呼びます。

[疑問2]
アトミック処理は、ロックを使用しないのに、どうやって排他的制御を実現しているのでしょうか??

用語を混同しているので意味不明な質問になってしまっています。
「ロックフリーは、ロック(排他制御)をしないのに、どうやってアトミック処理を実現しているのでしょうか??」という質問だと解釈して答えます。

自分の予想なのですが・・・これってもしかしてCPUにアトミック専用命令みたいなものが用意されている?・・・のでしょうか?

x86だと、レジスターのアラインメントに合わせたメモリアドレスに対する読み書きはアトミック実行が保証されていますし、ハード的にメモリバスをロックする仕組みも備わっており、いくつかの演算命令はLOCKプリフィックス付けることでアトミック実行になります。また、XCHG命令はそれ単体でアトミック実行を保証しています。
それらの機能をC/C++から簡単に利用するために、Windows SDKはInterlockedAddなどのアトミック演算関数を提供していますし、Linux等でも~~<intrin.h>ヘッダーをインクルードすれば~~[訂正]gcc独自の__sync_fetch_and系各種アトミック演算関数が利用できます。C++で<atomic>が実装される前は、それらの関数を使ってアトミック演算をしておりました。

[疑問3]
このvolatileはどのような効果を持っているのでしょうか?

最適化の抑止です。atomic_flagの仕様が判らないので正確には判りませんが、最適化されると著者が意図しない動作をすると考えたのでしょう。

となると、このvolatileは命令の実行順序と関係がありそうですね。
アトミックはvolatileの性質を含んでいるのでしょうか??

volatileは最適化しないことで結果的に書いたとおりに実行されることになりますが、それとアトミックとはまったく関係ありません。

[疑問4]
volatileとメモリバリアの違いがハッキリしません。

volatileはコンパイラの最適化抑制による順序付けであり、メモリバリアはCPUのアウトオブオーダー実行における順序付けです。メモリバリアには専用のCPU命令等が必要ですが、volatileはそんなことまではしてくれません。

[疑問5]
これも、CPUにメモリバリア専用命令みたいなのが用意されているのでしょうか?

x86だと、SFENCE/LFENCE/MFENCEという命令があります。あとは、特定の領域に対してオーダリングの利き具合を調整する機能もあるようです。
まぁ、その辺を直接いじるのは、OS開発者かコンパイラー開発者ぐらいなものでしょう。


[追記]
アトミック変数がvolatileの性質を含んでいるような気がしますが・・・

ここでいうアトミック変数が<atomic>で定義されるatomicクラスのオブジェクトのことであれば、volatileの性質を含んでいるというよりは、クラスの実装においてvolatileキーワードが各所で使われていて最適化による順序変更やコード削除を抑止する設計になっているので、いちいち変数定義時に付ける必要はないということですね。

質問中のコードにはなぜvolatileが登場しているんでしょうかね・・・

atomic_flagクラスのことでしょうか。著者が独自に作ったクラスだと思いますが、おそらくクラスの実装で適切にvolatileを使っていないので、オブジェクトに対して明示的にvolatileを付けないと意図しない動きになってしまうのでしょう。


[訂正]
Linuxでは<intrin.h>をインクルードすればアトミック演算関数が使えると書きましたが勘違いでした。別の要件で<intrin.h>を使っていててっきり同じものだと勘違いしていました。しかもintrin.hではなくx86intrin.hでしたし……。

投稿2018/12/24 15:37

編集2018/12/25 02:07
catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2018/12/25 03:20

すいません。 atomic_flag は C++ のライブラリですね。修正しました。 命令については理解しました。 そのような命令が用意されているんですね! メモリバリアはアウトオブオーダー実行の際に順序を守るために使用されるものという理解で正しいのでしょうか?
catsforepaw

2018/12/25 03:46

> atomic_flag は C++ のライブラリですね。修正しました。 確かにC++標準にありますね。下ではstd::を付けていてatomic_flagには付けていなかったので勘違いしてしまいました。 それならば、test_and_set関数の処理中にvolatileしている部分が必ずあるはずなので、わざわざvolatileを付ける必要はないように思うのですが……。よく判りませんね。単なる勘違いでしょうか。 > メモリバリアはアウトオブオーダー実行の際に順序を守るために使用されるものという理解で正しいのでしょうか? はい、それで合っています。
strike1217

2018/12/25 04:00

> ここでいうアトミック変数が<atomic>で定義されるatomicクラスのオブジェクトのことであれば、volatileの性質を含んでいるというよりは、クラスの実装においてvolatileキーワードが各所で使われていて最適化による順序変更やコード削除を抑止する設計になっている ああ!なるほど! ライブラリ自体にvolatileが使用されている・・・のでvolatileの性質を含んでいるように見える。わけですか!紛らわしい・・・ 本来であれば、atomicとvolatile は全く無関係なものだと理解して良いんですかね?
catsforepaw

2018/12/25 04:14

はい。まったく別の概念です。
strike1217

2018/12/25 05:34 編集

> 結局、問題に対処するために、Linuxカーネルではvolatileを使っている。アトミック操作ではすべての問題ある最適化を抑制できない。すると、volatileかつアトミック型を使わければならない。 このvolatileかつatomicである必要・・・というのは自分も調べていました。 近しいのはこれとかでしょうか? Should std::atomic be volatile? https://stackoverflow.com/questions/36496692/should-stdatomic-be-volatile
strike1217

2018/12/25 05:56 編集

> atomic代替のために、volatileを用いてならない。 また、volatileの代替としてatomicを用いてはならない。 C++ atomicライブラリはvolatileの性質を含んでいる。 しかし、volatile修飾を使ってそのライブラリを使用しなくてはならないケースが存在する。 (今回のstd::atomic_flagみたいな) あまりにも中途半端で混乱の原因になる。ということではないのでしょうか?
yohhoy

2018/12/25 06:17

(catsforepawさんコメント) > それならば、test_and_set関数の処理中にvolatileしている部分が必ずあるはずなので、わざわざvolatileを付ける必要はないように思うのですが……。よく判りませんね。単なる勘違いでしょうか。 私も同意で、書籍著者の誤認識と思われます。std::atomic_flagがスレッド間同期目的であれば、ここでのvolatile修飾は不要です。つけても"誤り"ではないので、動作上は単に冗長というだけですけど。 仮に、このコードがシグナルハンドラとの同期目的であればvolatile修飾が必要になりますが、シグナルハンドラの観点ではそもそも排他制御として成り立たないコードです。 ---- 「Linuxカーネルでのアトミック操作のためのvolatile変数」の話と、「C++11以降の標準アトミック変数」の話は分けて考えたほうがよいと思います。少なくとも、C++標準仕様のアトミック変数の振る舞い、C++標準メモリモデル、Linuxが対象とするCPUアーキテクチャ・アセンブリ言語でのアトミック性、該当アーキテクチャのメモリモデル、コンパイラが行う積極的な最適化テクニック、について理解していないと、Linus氏が指摘する問題を解釈するのは困難と思います...
yohhoy

2018/12/25 06:34 編集

> std::atomic_flag内のメソッドのオーバーロード解決のための修飾子だと理解したのですが・・・ > https://cpprefjp.github.io/reference/atomic/atomic_flag/test_and_set.html いいえ。test_and_setメンバ関数がvolatile修飾/非修飾版を提供するのは、単にvolatileなstd::atomic_flag変数と(非volatile)通常std::atomic_flag変数の両方にオーバーロード対応するための措置です。 http://www.open-std.org/Jtc1/sc22/wg21/docs/papers/2007/n2324.html > The functions and operations are defined to work with volatile objects, so that variables that should be volatile can also be atomic. The volatile qualifier, however, is not required for atomicity. > Many operations are volatile qualified. This qualification means that volatility is preserved when applying these operations to volatile objects. It does not mean that operatoins on non-volatile objects become volatile. # const修飾で考えると分かりやすいかもしれません。const修飾無しのメンバ関数は非constオブジェクトに対してのみ呼び出せますが、constオブジェクトの場合はconst修飾メンバ関数が必要となります。
strike1217

2018/12/25 06:49

あああ・・・ごめんなさい。 メソッドのオーバーロードというのは不適切だったかもしれません。 > volatileなstd::atomic_flag変数と(非volatile)通常std::atomic_flag変数の両方にオーバーロード対応するため 言いたいことは、これと全く同じだったのですが・・・
strike1217

2018/12/25 06:56

あ!そうか! すいません。 理解しました。自分の方が間違っていました。
strike1217

2018/12/25 07:11 編集

> 規格化されたアトミック操作は保証が弱すぎる。 以下、Effective modern C++ 抜粋です。 特殊メモリを操作する場合、冗長ロードや無意味ストアに見えるコードでもそのまま維持しなければならない点は、そのままstd::atomicがこの処理に不向きな理由になります。コンパイラは、std::atomicに対するこの種の冗長な演算を排除する事が認められているのです。 つまり、std::atomicの内部でvolatileを使っているにもかかわらず、その保証が弱すぎるため、結局、volatileとstd::atomicを併用しなくてはならない場面というのが存在する ということでしょう。
strike1217

2018/12/25 10:10

> メモリバリアはCPUのアウトオブオーダー実行における順序付けです。 これについて、1つだけ疑問があります。 メモリバリアはコンパイル時に順序を変更することもできないようにするのでしょうか? それとも、コンパイル時は、順序変更可能にしているのでしょうか?
catsforepaw

2018/12/25 11:11

yumetodoさん 私はカーネル屋でもコンパイラー屋でもプロセッサー屋でもないので、プロセッサー内部処理の最適化にまで踏み込むレベルになると理解が追いつかない部分がありますが、<atomic>のリファレンスを今一度確認してみたところ、`memory_order_consume`は、C++17で非推奨になっています。Linus氏が罵倒していたのもそれですね。また、他の順序付けに関しても、その定義がC++20で変更されているものがあります。何らかの不備があったということでしょうか。いずれにせよ、今の私ではすぐには理解するのは無理そうです……。
catsforepaw

2018/12/25 11:25

strike1217さん > メモリバリアはコンパイル時に順序を変更することもできないようにするのでしょうか? > それとも、コンパイル時は、順序変更可能にしているのでしょうか? ちょっとその質問の意味が判りかねるのですが、メモリバリアはコンパイルには関係ありません。CPUの内部の話です。CPUのアウトオブオーダー実行というのは、CPUがメモリから命令を読み込んで実行する際、メモリに書かれた順番とは異なる順番で実行することです。コンパイルによってすでに機械語になった命令の実行順の話なので、そこにコンパイラーが介在する余地はありません。
strike1217

2018/12/25 11:37

あ!以下を参考にしました。 https://ja.wikipedia.org/wiki/%E3%83%A1%E3%83%A2%E3%83%AA%E3%83%90%E3%83%AA%E3%82%A2#%E3%82%A2%E3%82%A6%E3%83%88%E3%82%AA%E3%83%96%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%E5%AE%9F%E8%A1%8C%E3%81%A8%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9%E3%81%AB%E3%82%88%E3%82%8B%E5%91%BD%E4%BB%A4%E9%A0%86%E5%BA%8F%E3%81%AE%E6%9C%80%E9%81%A9%E5%8C%96 > メモリバリア命令はハードウェアレベルの命令並べ替えに対するものである。コンパイラも最適化処理の一環として命令の並べ替えをすることがある。 つまり、実行時とコンパイル時の両方で命令順序が変更されないようにしたい場合は、volatileとメモリバリアの両方を併用しなくてはならない。 ということですね。
catsforepaw

2018/12/25 11:50

> つまり、実行時とコンパイル時の両方で命令順序が変更されないようにしたい場合は、volatileとメモリバリアの両方を併用しなくてはならない。 そういうことになりますね。volatileはソースコードに書かれた通りに(その順番で)機械語に変換されます。ただし、その機械語をCPUが実行する際、必ずしも順番通りに実行されるとは限らないため、それでは困る場合にメモリバリアで順序の入れ替えを抑制させます。
strike1217

2018/12/25 11:51

なるほど! 理解しました。
guest

0

こんにちは。

アトミック処理とは、ミュータックスと同じように排他的処理を提供するが、ミューテックスとは対象的にロックを使用しない。

つまり、アトミック処理 = ロックフリー 完全に同値なものだと解釈してよろしいのでしょうか?

std::is_lock_freeがあるということは、std::atomicはロックフリーな場合とそうでない場合があるようです。

アトミック処理は、ロックを使用しないのに、どうやって排他的制御を実現しているのでしょうか??

自分の予想なのですが・・・これってもしかしてCPUにアトミック専用命令みたいなものが用意されている?・・・のでしょうか?

具体的な命令は把握していませんが、CPUやバスコントローラ等のハードウェアで実装されているようです。当該処理を行っている間、バスを開放しなければマルチCPU環境でも整合性を保てますので。

このvolatileはどのような効果を持っているのでしょうか?

volatileは単なる最適化の抑止に過ぎません。バスの専有とは無関係です。

アトミックとは別にvolatileによく似ているのが、メモリフェンス(メモリバリア)の存在です。

メモリフェンスはstd::atomicと一緒に出てくる概念ですね。複数のCPU間でのアクセス上の整合性を維持するための機能のようです。
たぶん、マルチCPUシステム向けのバス設計やパイプライン処理、アウト・オブ・オーダー実行、メモリ・キャッシュ等に関するそれなりの知識がないと理解するのは超ハードなのかもと予想しています。

私は理解できなかったので、メモリフェンスに関して最適化はしない方針です。(デフォルトの一番効率が悪いけど確実な設定で使います。)よほどガチガチなものを作るのでない限り、性能劣化は事実上無視できるだろうと思います。

疑問2と似ているのですが・・・このメモリバリアと呼ばれるものはどうやって実現しているのでしょうか?

これも、CPUにメモリバリア専用命令みたいなのが用意されているのでしょうか?

アウトオブ・オーダー実行やキャッシュがある環境でマルチCPUからのアクセスをどうやって調停しているのか見当も付かないです。たぶん、ハードでうまいことやっているのだろうと思っています。

yohhoyさんの メモリモデル?なにそれ?おいしいの? が分かりやすいのです。私はこれを見て、とても私には理解できない話であることと、理解する必要まではないことを理解できました。

投稿2018/12/24 13:50

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2018/12/24 14:20

ちょっとリンク先を見てみます。
guest

0

アトミックとミューテックスを併用したプログラミングスタイルというものも存在するのでしょうか?

Linux の pthread mutex と Windows のクリティカルセクションオブジェクト(EnterCriticalSection等で使用されるオブジェクト)は規定の回数はアトミックロックによりロックを確保(スピンロックとか呼ばれる)しようとして、アトミックロックに失敗した場合のみカーネルオブジェクトの mutex によりロックを確保します。

質問の回答としては OS レベルの API ではパフォーマンスのためにそのような実装になっているものがあるというところですかね。

解説サイトを探してみたらありましたね。
http://www.tsoftware.jp/nptl/
このサイトによると pthread mutex の スピンロックは Posix 非標準とのこと・・・。

投稿2018/12/24 18:05

atata0319

総合スコア881

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2018/12/25 03:23

おお!なるほど! > アトミックロックによりロックを確保(スピンロックとか呼ばれる)しようとして、アトミックロックに失敗した場合のみカーネルオブジェクトの mutex によりロックを確保します。 アトミックとミューテックスを併用しているわけですね!
guest

0

アトミック処理ってのは、いわば1命令で終了する処理、ですね、
割り込み処理がどうかかろうが処理結果には影響しない処理です

疑問3:
volatileは、あらゆる最適化をされないことを保証するキーワードです
あくまで最適化されない、であって、排他であるかどうかは考慮されてません。
が、結果的に排他である場合が多いので、これまでそういう場面において多用されて来ましたが、近年、マルチコア状況下や投機実行動作時には排他されない場合がありえるということで、こういう用途にvolatileは適さないということが言われてきました。

疑問4:
前にも言ってますが、volatileは排他目的のキーワードではありません。
その性質上、結果的に排他している、というだけのはなしです。
これに対し、メモリバリアってのは、あらゆる場面において排他されることが保証されている処理となります

疑問5:
メモリバリアはCPUの専用の仕組み、あるいは専用の命令として組み込まれてます
volatileは、その性質上、処理的に割り込まれないようにしている、というのに対し、メモリバリアはハードウエア的に割り込まれない処理を実装してます

#まあ、専用の命令がないけど、内部的に割り込まれないような実装にしてる場合もありますが

投稿2018/12/24 14:06

y_waiwai

総合スコア87747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

[1] アトミック処理 = ロックフリー 完全に同値なものだと解釈してよろしいのでしょうか?

違います。lock-freeはアトミックの特殊な場合。
lock-freeが適用できるケースには限りがあります。

[2] アトミック処理は、ロックを使用しないのに、どうやって排他的制御を実現しているのでしょうか??

自分の予想なのですが・・・これってもしかしてCPUにアトミック専用命令みたいなものが用意されている?・・・のでしょうか?

CAS(Compare And Swap)ってCPU命令があります。これは1命令なので他のスレッドに割り込まれることがありません。

残る3つは...誰ぞお願い。

投稿2018/12/24 13:19

episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2018/12/24 13:43

> 違います。lock-freeはアトミックの特殊な場合。 なるほど!! 全くイコールなものではないわけですね。 > CAS(Compare And Swap)ってCPU命令があります。 ほぉぉ・・・そんな命令が!! 調べてみます。
guest

0

atomic代替のために、volatileを用いてならない。
また、volatileの代替としてatomicを用いてはならない。

ということは良いですよね。
volatile std::atomic_flag
std::atomic_flag
thisポインタにvolatileを付けているメソッドがありました。
おお!こんなところで出てくるとは!!

C++

1bool test_and_set(memory_order order = memory_order_seq_cst) volatile noexcept; 2bool test_and_set(memory_order order = memory_order_seq_cst) noexcept;

アトミック処理 = ロックフリーではなく。
アトミックとミューテックスを併用したスタイルも存在するということですね。
このスタイルは、ロックフリーに該当しない・・・ですね。

ロックフリープログラミングの手法を使うときは ABA 問題を避ける

ロックフリープログラミングの手法では、CAS (compare and swap) や LL/SC (load linked/store conditional) といった特別なアトミックプロセッサ命令、あるいは C の標準関数である atomic_compare_exchange を使う必要がある

これを見る限りだと、アトミック処理を使用しないで、ロックフリーを実現するのは不可能・・・ということですかね・・・


[追記]
メモリバリアには、アウトオブオーダー実行の命令順序の変更ができないようにします。
コンパイル時の命令順序変更をできないようにするには、メモリバリアでも可能なはずです。
(コンパイル時に変更できちゃったら、元も子もないような・・・)
つまり、メモリバリアは、volatileの代替になる場合がある。ということですよね。

std::atomicには、逐次一貫のため、内部にメモリバリアを用いていますね。
つまり、std::atomicは、volatileの一部の機能を含んでいることになりますよね。

ん???
なんか・・・変!
std::atomicを、命令実行順序の変更をさせないという目的においては、volatileの代替として利用することができることになりますね。

実際、Effective modern C++ にはそれに似たような事が書かれていますね。

データが置かれたメモリに対する読み書きの順序 と 命令の実行順序 は厳密に区別されなくてはならない・・・ということでしょうか?


[追記2]
追記の部分は完全に不適切です。
メモリバリア

メモリバリア命令はハードウェアレベルの命令並べ替えに対するものである。コンパイラも最適化処理の一環として命令の並べ替えをすることがある。

えーー。つまりvolatileの代替にメモリバリアを使用することはできない。ということですね。

投稿2018/12/25 05:24

編集2018/12/25 11:40
strike1217

総合スコア651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2018/12/27 16:32 編集

(不適切なの削除)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問