[解決済み] C++11でconstはスレッドセーフを意味するのか?
質問
私は、次のように聞いています。
const
というのは
スレッドセーフ
で
C++11
. それは本当ですか?
ということは
const
は、現在では
Java
's
synchronized
?
を使い果たしたのでしょうか? キーワード ?
どのように解決するのですか?
<ブロッククオート
私はそれを聞いて
const
というのは
スレッドセーフ
で
C++11
. それは本当ですか?
それは 多少 の通りです.
これは 標準言語 はスレッドセーフについて述べています。
<ブロッククオート[1.10/4] つの式の評価 衝突 もし一方がメモリ位置 (1.7) を変更し、もう一方が同じメモリ位置にアクセスするか変更するならば。
[1.10/21] プログラムの実行には データレース を含む場合、そのプログラムの実行は、異なるスレッドで2つの競合するアクションを含み、そのうちの少なくとも1つはアトミックではなく、どちらも他より前に発生しません。そのようなデータ競合は、未定義の動作になります。
の十分条件にほかなりません。 データ・レース が発生する十分条件に他なりません。
- ある物に対して同時に2つ以上のアクションが実行されていること、および
- そのうちの少なくとも 1 つは書き込みである。
は 標準ライブラリ はそれをベースにして、もう少し先に進みます。
[17.6.5.9/1] この節では,データ競合 (1.10) を防ぐために,実装が満たさなければならない要件を規定する。すべての標準ライブラリ関数は、特に指定がない限り、各要件を満たさなければならない。実装は、以下に指定された以外のケースでデータレースを防止することができます。
[17.6.5.9/3] C++標準ライブラリ関数は、現在のスレッド以外のスレッドからアクセス可能なオブジェクト (1.10) を直接または間接的に変更してはなりません。ただし、オブジェクトが関数の非 const を含む引数
this
.
に対する操作を期待していることを端的に表しています。
const
オブジェクトへの操作は
スレッドセーフ
. これは
標準ライブラリ
に対する操作がある限り、データ競合は起こらないということです。
const
オブジェクトを操作する限り、データ競合は発生しません。
- 読み込みのみで構成される -- つまり、書き込みはない -- あるいは
- 書き込みを内部的に同期させる。
もしこの期待があなたの型の一つで成り立たないのであれば、それを直接または間接的に
標準ライブラリ
が発生する可能性があります。
データ競合
. 結論から言うと
const
は
スレッドセーフ
を意味します。
標準ライブラリ
の観点で説明します。重要なのは、これは単に
契約
であり、コンパイラによって強制されることはなく、もしこれを破った場合は
未定義の動作
となり、自己責任となります。もし
const
があってもなくても、コード生成には影響しません。
データレース
--.
ということでしょうか。
const
と同等になったということでしょうか。 Java 'ssynchronized
?
いいえ . まったく......。
長方形を表す以下のような過度に単純化されたクラスを考えてみましょう。
class rect {
int width = 0, height = 0;
public:
/*...*/
void set_size( int new_width, int new_height ) {
width = new_width;
height = new_height;
}
int area() const {
return width * height;
}
};
は
メンバー関数
area
は
スレッドセーフ
ではありません。
const
でなく、読み込み操作だけで構成されているからです。書き込みはなく、少なくとも1回の書き込みが必要なのは
データ競争
が発生します。つまり
area
を好きなだけ呼び出すことができ、常に正しい結果が得られるということです。
という意味ではないことに注意してください。
rect
は
スレッドセーフ
. 実際,もし
area
を呼び出すと同時に発生したものです。
set_size
への呼び出しが同時に起こったとします。
rect
であれば
area
は古い幅と新しい高さに基づいて(あるいは文字化けした値に基づいて)その結果を計算することになるかもしれません。
しかし、それは大丈夫です。
rect
は
const
であることは期待されていません。
スレッドセーフ
ということになります。宣言されたオブジェクトは
const rect
と宣言されたオブジェクトは、一方では
スレッドセーフ
というのは、書き込みができないからです(そして、もしあなたが
const_cast
-と宣言されたものを
const
であれば、次のようになります。
未定義の振る舞い
と表示され、それでおしまいです)。
では、どういうことなのでしょうか?
議論のために、乗算演算は非常にコストがかかるので、可能な限り避けた方がよいと仮定しましょう。面積が要求された場合のみ計算し、将来再び要求された場合に備えてキャッシュしておくことができます。
class rect {
int width = 0, height = 0;
mutable int cached_area = 0;
mutable bool cached_area_valid = true;
public:
/*...*/
void set_size( int new_width, int new_height ) {
cached_area_valid = ( width == new_width && height == new_height );
width = new_width;
height = new_height;
}
int area() const {
if( !cached_area_valid ) {
cached_area = width;
cached_area *= height;
cached_area_valid = true;
}
return cached_area;
}
};
[この例があまりに人工的であるようなら、精神的に
int
を
非常に大きな動的に割り当てられた整数
であり、本来は
スレッドセーフ
であり、乗算は非常に高価です]。
は
メンバー関数
area
はもはや
スレッドセーフ
であり、現在書き込みを行っており、内部的に同期されていません。これは問題なのでしょうか?の呼び出しは
area
の一部として起こるかもしれません。
コピーコンストラクタ
のような、他のオブジェクトの
コンストラクタ
に対する何らかの操作によって呼び出された可能性があります。
標準コンテナ
に対する何らかの操作によって呼び出された可能性があり、その時点では
標準ライブラリ
として動作することを期待します。
読む
に関して
データ・レース
. しかし、私たちは書き込みをしているのです!
を置くと同時に
rect
の中に
標準コンテナ
--に直接または間接的に入ることになります。
契約
との
標準ライブラリ
. で書き込みを続けるには
const
関数で書き込みを行いながら、そのコントラクトを尊重するためには、書き込みを内部的に同期させる必要があります。
class rect {
int width = 0, height = 0;
mutable std::mutex cache_mutex;
mutable int cached_area = 0;
mutable bool cached_area_valid = true;
public:
/*...*/
void set_size( int new_width, int new_height ) {
if( new_width != width || new_height != height )
{
std::lock_guard< std::mutex > guard( cache_mutex );
cached_area_valid = false;
}
width = new_width;
height = new_height;
}
int area() const {
std::lock_guard< std::mutex > guard( cache_mutex );
if( !cached_area_valid ) {
cached_area = width;
cached_area *= height;
cached_area_valid = true;
}
return cached_area;
}
};
なお、ここでは
area
機能
をスレッドセーフにしました。
しかし
rect
はまだ
スレッドセーフ
. への呼び出しは
area
への呼び出しと同時に起こる
set_size
への代入はまだ間違った値を計算することになるかもしれません。
width
と
height
はミューテックスで保護されません。
もし本当に
スレッドセーフ
rect
を保護するために、同期プリミティブを使用することになります。
スレッドセーフでない
rect
.
を使い切っているのでしょうか? キーワード ?
はい、そうです。彼らは キーワード を使い果たしているのです。
ソース
:
あなたは知らない
const
と
mutable
-
ハーブ・サッター
関連
-
[解決済み】C++ 非推奨の文字列定数から「char*」への変換について
-
[解決済み】システムが指定されたファイルを見つけられませんでした。
-
[解決済み】エラー。引数リストに一致するコンストラクタのインスタンスがない
-
[解決済み] explicit キーワードの意味は?
-
[解決済み] C++11では、標準化されたメモリモデルが導入されました。その意味するところは?そして、C++プログラミングにどのような影響を与えるのでしょうか?
-
[解決済み] const int*、const int * const、int const *の違いは何ですか?
-
[解決済み] Static readonly」対「const」。
-
[解決済み] C++11の'typedef'と'using'の違いは何ですか?
-
[解決済み] C++11のT&&(ダブルアンパサンド)の意味とは?
-
[解決済み] lockステートメントは、ボンネットの中で何をするのでしょうか?
最新
-
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 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】クラステンプレートの引数リストがない
-
[解決済み】C++でユーザー入力を待つ【重複あり
-
[解決済み] クラスにデフォルトコンストラクタが存在しない。
-
[解決済み】エラー:strcpyがこのスコープで宣言されていない
-
[解決済み] 非静的データメンバの無効な使用
-
[解決済み] [Solved] インクルードファイルが開けません。'stdio.h' - Visual Studio Community 2017 - C++ Error
-
[解決済み】1つ以上の多重定義されたシンボルが見つかる
-
[解決済み】クラスのコンストラクタへの未定義参照、.cppファイルの修正も含む
-
[解決済み】Enterキーを押して続行する
-
[解決済み] 警告:暗黙の定数変換でのオーバーフロー