XPの頃までWindowsAPIになかった 条件変数:Condition-VariableがVista以降サポートされて、
スレッドの同期が楽になりました。
# つかWindowsAPIをハダカで使うよか、Boost.ThreadやTBBに任せるが吉なんだけども。
Condition-Variableのお試しに ランデブー(Rendezvous) Boost.Thread でいうところの バリア(barrier) を作ってみる。
ランデブーは同期オブジェクトのひとつで、「待ち合わせ」をサポートするよ。
rendezvous anchor(N);
みたくコンストラクトする。引数Nは待ち合わせるスレッドの数。
各スレッドで anchor.wait() すると待ち合わせ状態となりブロックされるんだけども、
N個めのスレッドが anchor.wait() した途端に全員が揃ってブロックが解除され、一斉に走り出すのね。
#include <iostream>
#include <array>
#include <cstdlib>
#include <Windows.h>
class rendezvous {
public:
rendezvous(unsigned int count)
: threshold_(count), count_(count), generation_(0) {
InitializeCriticalSection(&mutex_);
InitializeConditionVariable(&condition_);
if (count == 0) {
throw std::invalid_argument("count cannot be zero.");
}
}
~rendezvous() {
DeleteCriticalSection(&mutex_);
}
bool wait() {
EnterCriticalSection(&mutex_);
unsigned int gen = generation_;
if (--count_ == 0) {
generation_++;
count_ = threshold_;
WakeAllConditionVariable(&condition_);
LeaveCriticalSection(&mutex_);
return true;
}
while ( gen == generation_ ) {
SleepConditionVariableCS(&condition_, &mutex_, INFINITE);
}
LeaveCriticalSection(&mutex_);
return false;
}
private:
CRITICAL_SECTION mutex_;
CONDITION_VARIABLE condition_;
unsigned int threshold_;
unsigned int count_;
unsigned int generation_;
};
using namespace std;
// 息の合わないかけっこ
DWORD WINAPI ready_set_go_normal(LPVOID arg) {
for ( int t = 0; t < 3; ++ t ) {
Sleep(rand()%20*100);
cout << "位置について";
Sleep(rand()%20*100);
cout << "よーい";
Sleep(rand()%20*100);
cout << "ドン!";
}
return 0;
}
// 阿吽の呼吸でかけっこ
DWORD WINAPI ready_set_go_rendezvous(LPVOID arg) {
rendezvous& anchor = *static_cast<rendezvous*>(arg);
for ( int t = 0; t < 3; ++ t ) {
Sleep(rand()%20*100);
anchor.wait();
cout << "位置について";
Sleep(rand()%20*100);
anchor.wait();
cout << "よーい";
Sleep(rand()%20*100);
anchor.wait();
cout << "ドン!";
}
return 0;
}
const int N = 3;
void run(LPTHREAD_START_ROUTINE fun, rendezvous* pren) {
array<HANDLE,N> threads;
for ( int i = 0; i < N; ++i ) {
threads[i] = CreateThread(NULL, 0, fun, pren, 0, 0);
}
WaitForMultipleObjects(N, &threads[0], TRUE, INFINITE);
}
int main() {
run(&ready_set_go_normal,0);
cout << endl << endl;
rendezvous anchor(N);
run(&ready_set_go_rendezvous,&anchor);
cout << endl;
}
息が合ってないと...
位置について位置について位置についてよーいよーいよーいドン!ドン!位置についてドン
!位置について位置についてよーいよーいよーいドン!ドン!ドン!位置について位置につい
て位置についてよーいよーいよーいドン!ドン!ドン!
ランデブー使えば...
位置について位置について位置についてよーいよーいよーいドン!ドン!ドン!位置につい
て位置について位置についてよーいよーいよーいドン!ドン!ドン!位置について位置につ
いて位置についてよーいよーいよーいドン!ドン!ドン!