質問: 0; work_lock(d); } ``` もし、上記のコードの2つの構造体にいっぺんに排他をかけたい場合、 1つのクラスの中に2つの構造体を入れてmutex宣言をしてあげれば、両構造体に排他かかりますよね?(以下のような状態) ``` class Exclusive { public: struct Data { int data; }; struct Data_2 { int data_2; }; std::mutex mtx; } ```
回答: 質問文をみるに「構造体という型(type)」「関数などソースコード上のスコープ(scope)」「実行時の制御フロー(contorl flow)」で混同されているように思えます。 * C++の場合、型情報それ自体は排他制御には何の影響もあたえません。同一構造体のメンバにデータ(`data`)とmutex(`mtx`)を含めるのは、一般にメンテナンス性が良いからそうするというだけです。 * 排他制御の設計は、制御フロー=「スレッドがどんな順序で命令を実行するか」に着目して必要があります。これはソースコード上で表現されるスコープ(レキシカル・スコープ)とはまた別の話です。 * C++の場合、排他制御で保護する変数(`data`)の読み書き操作と排他制御を実現するmutex(`mtx`)のロック操作を正しく対応付けるのは、完全にC++プログラマの責任となっています。C++コンパイラは何も助けてくれません。 * Mutex(`std::mutex`)は、排他制御を実現する道具(の一つ)です。`std::lock_guard`は、レキシカル・スコープに基づいた自動Mutexロック獲得/解放を行ってくれる補助道具です。 排他制御の設計では「どの**データ**を保護するか」をまず考え、**実行時の制御フロー上で**該当データ読み書き操作がロック区間内に正しく含まれるようにします。 実装観点ではMutexはコード区間を排他的に実行する仕組みですが、概念的には共有資源への**アクセスを排他的に制御**するものです。 > > それぞれの構造体にmutex宣言をし、 > > そのmutexの変数にstd::lock_guard lock(ここにmutecx変数)をしてあげれば > > 対象の構造体にロックがかかる認識で合っているでしょうか? > > > 厳密には「いいえ」。構造体(型)にロックがかかる訳ではありません。 ある構造体のメンバになっているmutex(`mtx`)のロック操作と、同構造体のメンバ変数(`data`)操作をセットで扱うのは、プログラマであるあなたの責任になります。 両者を近くに配置することでコードの保守性が良くよくなるという効果はありますが、同一構造体のメンバ変数だからといってコンパイル時やプログラム実行時に自動的に面倒を見てくれることは何もありません。 ある変数(`data`)への読み書き操作を行うときには、**対応する**mutex(`mtx`)が常にロック済みであることを保証するよう、C++プログラマが明示的にコード記述する必要があります。 (厳密には全スレッドRead Onlyであればロック不要なケースもありますが、話を単純化するため無視します。より詳細はこちらの記事もご参考に。) > > もし、上記のコードの2つの構造体にいっぺんに排他をかけたい場合、 > > 1つのクラスの中に2つの構造体を入れてmutex宣言をしてあげれば、両構造体に排他かかりますよね? > > > 「いいえ」。mutexとデータが同じ構造体のメンバであることは、本質的には無関係です。 プログラマであるあなたの責任で、ロック操作とデータアクセスを正しいセットで取り扱う必要があります。