N個のスレッドの待ち合わせ場所を用意する。
各スレッドがそこでwait
すると、
全員が揃うまで各スレッドは待ち状態となり、
全員が揃った時点で全スレッドの待ちが解ける。
こんな待ち合わせ場所(rendezvous
)があれば、各スレッドをひとつずつjoin
しなくていい。
#include <thread>
#include <mutex>
#include <condition_variable>
#include <stdexcept>
/*
* rendezvous(ランデブー) あるいは barrier(バリア)
*/
class rendezvous {
public:
rendezvous(unsigned int count)
: threshold_(count), count_(count), generation_(0) {
if (count == 0) { throw std::invalid_argument("count cannot be zero."); }
}
bool wait() {
std::unique_lock<std::mutex> lock(mutex_);
unsigned int gen = generation_;
if (--count_ == 0) {
generation_++;
count_ = threshold_;
condition_.notify_all();
return true;
}
condition_.wait(lock, [&](){return gen != generation_; });
return false;
}
private:
std::mutex mutex_;
std::condition_variable condition_;
unsigned int threshold_;
unsigned int count_;
unsigned int generation_;
};
/* おためし */
#include <iostream>
#include <array>
#include <mutex>
using namespace std;
int main() {
const int N = 4; // 子スレッド数
array<thread,N> threads;
rendezvous period(N);
rendezvous quit(N+1);
mutex mtx;
for ( int i = 0; i < N; ++i ) {
threads[i] = thread([&,i]() {
{ lock_guard<mutex> guard(mtx); cout << "thread " << i << " 位置について\n"; }
period.wait(); // 全スレッドが揃うまで待機
{ lock_guard<mutex> guard(mtx); cout << "thread " << i << " よーい\n"; }
period.wait(); // 全スレッドが揃うまで待機
{ lock_guard<mutex> guard(mtx); cout << i << " どん!\n"; }
quit.wait();
});
}
quit.wait(); // 全スレッドが wait するまで待つ
cout << "はい、次の組...\n";
for (thread& thr : threads ) { thr.join(); }
}
/* 実行結果:
thread 0 位置について
thread 1 位置について
thread 2 位置について
thread 3 位置について
thread 3 よーい
thread 2 よーい
thread 0 よーい
thread 1 よーい
1 どん!
0 どん!
3 どん!
2 どん!
はい、次の組...
*/