LoginSignup
13
12

More than 5 years have passed since last update.

C++でJavaっぽい、いやJava以上のsynchronized

Posted at

C++11以降だとstd::mutexとstd::lock_guardがありますし、これらは簡単なクラスだから古いC++でも数秒で自作できますし、でも排他スコープが明確なJava/C#のsynchronizedの記法がうらやましいなーとこんなマクロ書いちゃうこと多いですよね。(よね?)

#define synchronized(monitor) \
  if (auto __lock = std::make_unique<std::lock_guard<std::mutex>>(monitor))

こういうの定義しておくと

std::vector<int> data_;  // いろんなスレッドから読み書きするデータ
std::mutex monitor_;     // mutexオブジェクトを宣言しておいて

...

synchronized (motinor_) {
  // 排他制御された処理
  data_.doSomething();
}

Javaやあっ。

さてここからはJavaを超えに行きます。
プログラマの意図は「data_を自スレッドしか触っていないことを保証したい」であって、monitor_という存在は意図よりも低レベル、ノイズです。Javaだとdata_そのものにモニタの役割もさせてしまう(synchronized(data_)と書く)こともまあできますが、これはあまりよろしくない技法だから普通はmonitor_を別に用意するものです。
C++ならそれもマクロに用意させてプログラマの目から隠せる。

// 先ほどのsynchronizedの定義に追加します。

// モニタ変数の名前は _mutex_【対象変数名】 だ
#define MONITOR_OF(var) _mutex_ ## var

// 変数宣言とそれ専用のモニタ変数宣言をやってくれる
#define DECLARE_THREAD_SAFE(type, var) \
  type var; \
  std::mutex MONITOR_OF(var);

// 独占使用したい変数を指定する記法
#define exclusive(var) synchronized(MONITOR_OF(var))

こうすると、data_の独占使用はこうなります。

DECLARE_THREAD_SAFE(std::vector<int>, data_)  // いろんなスレッドから読み書きするデータ

...

exclusive (data_) {
  // 排他制御された処理
  data_.doSomething();
}

synchronizedマクロですが、if構文の枠に乗せるためにmake_uniqueしてるのがなんか迂遠で汚らしいですね。なんかいい書き方ありますかね。ifでなくfor使うとか?

13
12
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
12