マルチスレッドのConditionについて

# はじめに
[core.sync.condition.Condition](https://dlang.org/phobos/core_sync_condition.html#.Condition)
「え？ただのConditionだよ？知ってるよね？」みたいに書かれてる。
つらい。

# Conditionとは
Java由来？のマルチスレッドの同期システムです。~~Javaとか滅せ。~~
コンストラクタの引数にしたMutexを使って、ロックの解除を待ったり、通知を待ったりします。
Conditionでwaitした場合、Mutexがロックされていなくて、かつConditionに通知(notify)されるまでスレッドを停止します。

# 例(1) ロック中にwaitした場合
Mutexをロックしているときにwaitすると、そのMutexのロックを解除して、待機状態に入ります。別スレッドがMutexをロックすると、notifyされても、Mutexがロック解除されるまでは待機を維持します。

```d
import std.stdio, std.parallelism, core.thread, core.sync.condition, core.sync.mutex;

void main()
{
	auto cond = new Condition(new Mutex);
	
	//     000    100    200    300    400    500    600 [ms]
	// 1:  1xxxxxxxxxxxxxooooooo-------6xxxxxx7     8!
	// 2:         2------xxxxxx3!4xxxx5oooooooooooooo9
	// 【凡例】
	//     x : ロック中
	//     - : 他のロック解除待ち
	//     o : 他からの通知待ち
	//     ! : 通知
	
	//     000    100    200    300    400    500    600 [ms]
	// 1:  1xxxxxxxxxxxxxooooooo-------6xxxxxx7     8!
	taskPool.put(task(
	{
		Thread.sleep(0.msecs);
		writeln(1);
		cond.mutex.lock();
		Thread.sleep(200.msecs);
		
		// ここで一度ロックが外れる
		// →3での通知を受けて再度ロックを試みて解除を待つ
		//   →5でロック解除されて制御が戻る
		cond.wait();
		
		writeln(6);
		Thread.sleep(100.msecs);
		
		writeln(7);
		cond.mutex.unlock();
		
		Thread.sleep(100.msecs);
		writeln(8);
		cond.notify();
	}));
	//     000    100    200    300    400    500    600 [ms]
	// 2:         2------xxxxxx3!4xxxx5oooooooooooooo9
	taskPool.put(task(
	{
		Thread.sleep(100.msecs);
		
		writeln(2);
		cond.mutex.lock();
		
		Thread.sleep(100.msecs);
		writeln(3);
		cond.notify();
		writeln(4);
		Thread.sleep(100.msecs);
		writeln(5);
		// ここで一度ロックが外れる
		// →8での通知を受けて再度ロックを試みてロック成功
		cond.wait();
		
		writeln(9);
		cond.mutex.unlock();
	}));
	taskPool.finish();
}
```

# 例(2) ロック解除中にwaitした場合
ロック解除中にwaitした場合、ほかのスレッドからnotifyされるまで待機します。

```d
import std.stdio, std.parallelism, core.thread,
       core.sync.condition, core.sync.mutex;

void main()
{
	auto cond = new Condition(new Mutex);
	
	//     000    100    200    300    400    500    600 [ms]
	// 1:  1ooooooooooooo-------6xxxxxx7     8!
	// 2:         2xxxxx3!4xxxx5oooooooooooooox9
	// 【凡例】
	//     x : ロック中
	//     - : 他のロック解除待ち
	//     o : 他からの通知待ち
	//     ! : 通知
	
	//     000    100    200    300    400    500    600 [ms]
	// 1:  1ooooooooooooo-------6xxxxxx7     8!
	taskPool.put(task(
	{
		Thread.sleep(0.msecs);
		writeln(1);
		
		// 通知待ち
		// →3での通知を受けてロックを試みて解除を待つ
		//   →5でロック解除されて制御が戻る
		cond.wait();
		
		writeln(6);
		Thread.sleep(100.msecs);
		
		writeln(7);
		cond.mutex.unlock();
		
		Thread.sleep(100.msecs);
		writeln(8);
		cond.notify();
	}));
	//     000    100    200    300    400    500    600 [ms]
	// 2:         2xxxxx3!4xxxx5oooooooooooooox9
	taskPool.put(task(
	{
		Thread.sleep(100.msecs);
		
		writeln(2);
		cond.mutex.lock();
		
		Thread.sleep(100.msecs);
		writeln(3);
		cond.notify();
		writeln(4);
		Thread.sleep(100.msecs);
		writeln(5);
		// ここで一度ロックが外れる
		// →8での通知を受けて再度ロックを試みてロック成功
		cond.wait();
		
		writeln(9);
		cond.mutex.unlock();
	}));
	taskPool.finish();
}
```

# D言語特有の問題
Conditionは性質上、当たり前のようにスレッド間で共有される資源です。つまり、sharedストレージクラスにしたくなる時があります。
しかしながら、Condition(をはじめとするcore.sync.\*のモジュール)はsharedなメンバ関数を提供していません。
今我々にできる最良の手順は、castによってsharedを外してしまうことです。