#include // using std::mutex, std::unique_lock #include // using std::condition_variable #include // using std::async, std::future #include // using std::invalid_argument #include // using std::array namespace { class barrier { std::mutex mutex; int sequence_no, count; const int total_count; std::condition_variable condition; public: explicit barrier(int total_count) : sequence_no(), count(), total_count(total_count) { if(total_count < 1) throw std::invalid_argument("barrier(total_count < 1)"); } void wait() { std::unique_lock lock(mutex); if(! count) { /* we are the first thread to arrive here. Let's set up the barrier */ ++sequence_no; count = total_count; } if(--count) { const int own_seq_no = sequence_no; auto is_complete = [own_seq_no, this]() noexcept -> bool { return this->count == 0 || this->sequence_no != own_seq_no; }; condition.wait(lock, is_complete); } else { # ifdef WAKE_AFTER lock.unlock(); # endif condition.notify_all(); } } }; void threadfun(barrier* shared_barrier, int iterations) { for(int i = 0; i < iterations; ++i) shared_barrier->wait(); } } int main() { const int iterations = 1000; constexpr int threads = 16; std::array, threads> futures; barrier shared_barrier(threads); for(std::future& future: futures) future = std::async(std::launch::async, threadfun, &shared_barrier, iterations); for(std::future& future: futures) future.get(); }