かなり単純な質問がありますが、答えは私にはわからないようです。同じ C++ クラスの複数のオブジェクトがあり、各オブジェクトが独自のスレッドにある場合、同時アクセスの問題に注意する必要がありますか? それとも、個別のインスタンスに対して自動的にスレッドセーフですか? もちろん、静的メソッドの問題が予想されますが、インスタンス メソッドは?
6 に答える
各スレッドに個別のオブジェクトがある場合は問題ありません。ただし、そのクラスに静的メンバー変数がある場合、問題が発生する可能性があります。
明らかに、スレッド関数がグローバルまたは共有データにアクセスしている場合、これは問題のクラス オブジェクトのデータにのみ適用され、通常のマルチスレッドの問題が適用されます。
場合によります。多くの場合、クラスの 1 つのインスタンスは、他のインスタンスの操作から独立しています。これが単一スレッドの場合であれば、複数スレッドでも同様です。
たとえば、Point を表す値型クラスを考えてみましょう。
class Point {
public:
int x, y, z
};
あるスレッドのこのクラスのインスタンスは、別のスレッドの別のインスタンスに対する操作の影響を受けません。
ただし、クラスのインスタンスは他のオブジェクトと対話できます。2 つのインスタンスが同じオブジェクトと対話できる場合、はい、スレッド セーフについて考慮する必要があります。
インスタンス変数はすべて独立しています。したがって、インスタンス メソッドがインスタンス変数とローカル変数のみを使用する場合、スレッド セーフについて心配する必要はありません。
あるオブジェクトのスレッドが別のオブジェクトのメソッドを呼び出さない限り、問題はありません。
ただし、再帰的なメソッドがあり、メソッドでミューテックスを取得している場合は、まだデッドロックが発生する可能性があります。その場合は、再帰的ミューテックスを使用する必要があります。
大まかに、C++ の項目を 4 つのカテゴリに分類できます。
- 読み取り専用: リテラル、定数、関数などはコードの実行中に変更できないため、本質的に安全に共有できます
- グローバル変数: 名前空間スコープのグローバル、クラスの静的属性、関数内のローカル静的などを変更できるため、適切なマルチスレッド対応メカニズムを使用する必要があります
- スレッドローカル変数: 上記のすべてですが、
thread_local
ストレージ修飾子でマークされています。次のポイントを参照してください - インスタンス変数: クラスまたは構造体の属性、関数のローカル変数などは、明示的に共有されていない限り、本質的に安全に使用できます
つまり、メソッドや関数を気にする必要はなく、定数も自由に共有できます。
中間の範囲では、少なくともアクセス時に適切な同期を確保せずに、ローカル変数を共有しないようにします (不注意であっても)。
そして最後に、グローバルには細心の注意を払ってください。
あなたの質問の根底には、オブジェクトがメモリ内でどのように配置されるかについての質問があります。静的データ メンバー (これはまれです) が関与していないと仮定すると、各オブジェクトは同じ型の他のオブジェクトから独立しています。これは、メモリ内に配置されたオブジェクト自体が、オブジェクトのいくつかのデータ メンバーのみで構成されているためです。たとえば、型定義
class Location {
private:
double latitude1;
double longitude1;
public:
double latitude () const { return latitude1; }
double longitude() const { return longitude1; }
Location(const double lat0, const double long0) {
latitude1 = lat0;
longitude1 = lon0;
}
// Calculate the Location at exactly the furthest
// point on earth (implemented elsewhere).
Location antipode();
};
タイプの個別のオブジェクトが別の場所でインスタンス化されているとします。
Location my_loc(-100.0, 35.0);
const Location your_loc(15.0, 45.5);
次に、my_loc
それ自体はメモリ内の double のペア(この場合、スタック上の連続する double のペア) だけで構成されます。そしてyour_loc
それ自体は、別個の double のペアだけで構成されます。つまり、データに関する限り、aLocation
は 2 つの double の構造体にすぎません。
しかし、あなたは尋ねます: コンストラクターや などantipode()
はどうですか? 答えは、それぞれがクラスに対して 1 回だけ存在し、メモリに関する限り、データと直接関連付けられていないということです。データを関数に関連付けるのはコンパイラだけです。スレッドはそれを気にしません。
これまでのことを踏まえて考えてみると、あなたが見落としていた答えがあなたに落ち着くのではないかと思われます。