#include <mutex>
// using std::mutex, std::unique_lock
#include <condition_variable>
// using std::condition_variable
#include <future>
// using std::async, std::future
#include <stdexcept>
// using std::invalid_argument
#include <array>
// 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<std::mutex> 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<std::future<void>, threads> futures;
barrier shared_barrier(threads);
for(std::future<void>& future: futures)
future = std::async(std::launch::async, threadfun, &shared_barrier,
iterations);
for(std::future<void>& future: futures)
future.get();
}
Comments