4

Herb Sutter ( http://isocpp.org/blog/2012/12/you-dont-know-const-and-mutable-herb-sutter ) によると、C++11 では、const メソッドはオブジェクトのビットを変更してはなりません。または、変更可能なデータメンバーがある場合は、内部同期を実行する必要があります (例: ミューテックスを使用)。

複数のスレッドからアクセスしているグローバル オブジェクトがあり、そのオブジェクトに変更可能なメンバーがあるとします。議論のために、クラスのソースを変更できないと仮定しましょう (サードパーティによって提供されます)。

C++98 では、これらのスレッドはグローバル ミューテックスを使用して、このオブジェクトへのアクセスを同期します。したがって、アクセスには単一のミューテックス ロック/ロック解除が必要です。

ただし、C++11 では、このオブジェクトに対する const メンバー関数呼び出しも内部同期を呼び出すため、このオブジェクトに対する 1 回の const 関数呼び出しで 2 回のロック/ロック解除操作が必要になる可能性があります (関数の数によってはそれ以上)。単一のスレッドから呼び出します)。const はライターに対して何もしないように見えるため、グローバルミューテックスがまだ必要であることに注意してください (const 以外のメソッドの 1 つが const メソッドを呼び出した場合にライターを遅くする可能性を除いて)。

それで、私の質問は次のとおりです。すべてのクラスを C++ でこのようにする必要がある場合 (少なくとも STL で使用できるようにするため)、これは過度の同期手段につながりませんか?

ありがとう

編集:いくつかの説明:

  1. C++11では、constメンバー関数が内部的に同期されていない限り(または書き込みを実行していない場合)、標準ライブラリでクラスを使用できないようです。

  2. C++11 は同期コード自体を自動的に追加しませんが、標準ライブラリに準拠したクラスは、C++98 では同期を必要としませんが、C++11 では同期が必要です。したがって、C++98 では可変メンバーの内部同期を行わなくても問題は解決できますが、C++11 ではできません。

4

2 に答える 2

6

はい、あなたは絶対に正しいです。オブジェクトをこれらのガイドラインに従うようにする必要があるため、C++11 ではオブジェクトへのアクセスが遅くなる可能性があります。次の場合のみ:

  1. クラスには、メンバー関数が変更するmutableメンバーがあります。const

  2. オブジェクトは複数のスレッドからアクセスされています。

これらの少なくとも 1 つが正しくないことを確認した場合、何も変わりません。複数のスレッドからアクセスされるオブジェクトの数は、常に可能な限り最小限にする必要があります。また、変更可能なメンバーを持つクラスの数は最小限にする必要があります。つまり、オブジェクトの最小セットの最小セットについて話しているのです。

それでも…必要なのは、データ競合が壊れないことだけです。変更可能なデータが何であるかにもよりますが、これは単にアトミック アクセスである可能性があります。

ここで問題がわかりません。標準ライブラリ オブジェクトの中には、変更可能なメンバーを持つものはほとんどありません。可変メンバーを必要とする 、 、 などbasic_stringvector合理的な実装を見つけることはできません。map

C++11では、constメンバー関数が内部的に同期されていない限り(または書き込みを実行していない場合)、標準ライブラリでクラスを使用できないようです。

これは正しくありません。あなたは間違いなくそうすることができます。できないことは、それらの可変メンバーに対して「書き込みを実行する」方法で、複数のスレッドにわたってそのクラスにアクセスしようとすることです。その特定の方法でスレッド間でその C++11 クラスを介してそのオブジェクトにアクセスしない場合は、問題ありません。

はい、使用できます。ただし、独自のクラスが提供する保証しか得られません。標準ライブラリ クラスを介して不合理な方法でクラスを使用した場合(constメンバー関数が適切に同期されていない、constまたは適切に同期されていないなど)、それはライブラリではなくあなたのせいです。

したがって、C++98 では可変メンバーの内部同期を行わなくても問題は解決できますが、C++11 ではできません。

それは、ローマ帝国に戻ってコンピューター犯罪を回避できると言っているようなものです. もちろんできます。当時はコンピューターがありませんでした。そのため、彼らはコンピューター犯罪が何であるかを知りませんでした。

C++98/03 には「スレッド化」の概念がありませんでした。したがって、標準には「内部同期」の概念がないため、「回避」できるものとできないものは、定義も未定義もありませんでした。シーザーの時代にハッキング法が何であったかを尋ねるよりも、標準についてその質問をすることは意味がありませんでした.

C++11 では実際にこの概念と競合状態の概念が定義されているため、C++11 は「内部同期を行わなくても済む」タイミングを判断できます。

別の言い方をすれば、2 つの標準があなたの質問にどのように答えるかを示します:標準ライブラリでmutable宣言されたメンバー関数を介してメンバーにアクセスした場合、メンバーで発生する可能性のあるデータ競合の結果はどうなりますか?const

C++11: 関数によってアクセスされたときに、内部メンバーでデータ競合が発生しませんconst。このような関数のすべての標準ライブラリ実装は、データ競合が発生しないように実装する必要があります。

C++98/03: データ競合とは?

于 2013-06-07T21:58:28.823 に答える