barrier
parent
9a437ec75a
commit
60f77961fb
|
@ -1,7 +1,7 @@
|
||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
include(cmake/color.cmake)
|
include(cmake/color.cmake)
|
||||||
|
|
||||||
set(BLT_VERSION 0.18.7)
|
set(BLT_VERSION 0.18.8)
|
||||||
set(BLT_TEST_VERSION 0.0.1)
|
set(BLT_TEST_VERSION 0.0.1)
|
||||||
|
|
||||||
set(BLT_TARGET BLT)
|
set(BLT_TARGET BLT)
|
||||||
|
|
|
@ -19,20 +19,91 @@
|
||||||
#ifndef BLT_THREAD_H
|
#ifndef BLT_THREAD_H
|
||||||
#define BLT_THREAD_H
|
#define BLT_THREAD_H
|
||||||
|
|
||||||
|
#include <blt/std/types.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
#include <utility>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <blt/std/logging.h>
|
#include <blt/std/logging.h>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
namespace blt
|
namespace blt
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class barrier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit barrier(blt::size_t threads, std::optional<std::reference_wrapper<std::atomic_bool>> exit_cond = {}):
|
||||||
|
thread_count(threads), threads_waiting(0), use_count(0), exit_cond(exit_cond), count_mutex(), cv()
|
||||||
|
{
|
||||||
|
if (threads == 0)
|
||||||
|
throw std::runtime_error("Barrier thread count cannot be 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
barrier(const barrier& copy) = delete;
|
||||||
|
|
||||||
|
barrier(barrier&& move) = delete;
|
||||||
|
|
||||||
|
barrier& operator=(const barrier& copy) = delete;
|
||||||
|
|
||||||
|
barrier& operator=(barrier&& move) = delete;
|
||||||
|
|
||||||
|
~barrier() = default;
|
||||||
|
|
||||||
|
void wait()
|
||||||
|
{
|
||||||
|
// (unique_lock acquires lock)
|
||||||
|
std::unique_lock lock(count_mutex);
|
||||||
|
std::size_t current_uses = use_count;
|
||||||
|
|
||||||
|
if (++threads_waiting == thread_count)
|
||||||
|
{
|
||||||
|
threads_waiting = 0;
|
||||||
|
use_count++;
|
||||||
|
cv.notify_all();
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
if constexpr (BUSY_LOOP_WAIT > 0) // NOLINT
|
||||||
|
{
|
||||||
|
lock.unlock();
|
||||||
|
for (blt::size_t i = 0; i < BUSY_LOOP_WAIT; i++)
|
||||||
|
{
|
||||||
|
if (use_count != current_uses || (exit_cond && exit_cond->get()))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lock.lock();
|
||||||
|
}
|
||||||
|
cv.wait(lock, [this, ¤t_uses]() {
|
||||||
|
return (use_count != current_uses || (exit_cond && exit_cond->get()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void notify_all()
|
||||||
|
{
|
||||||
|
cv.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
blt::size_t thread_count;
|
||||||
|
blt::size_t threads_waiting;
|
||||||
|
blt::size_t use_count;
|
||||||
|
std::optional<std::reference_wrapper<std::atomic_bool>> exit_cond;
|
||||||
|
std::mutex count_mutex;
|
||||||
|
std::condition_variable cv;
|
||||||
|
|
||||||
|
// improves performance by not blocking the thread for n iterations of the loop.
|
||||||
|
// If the condition is not met by the end of this loop we can block the thread.
|
||||||
|
static constexpr blt::size_t BUSY_LOOP_WAIT = 200;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @tparam queue should we use a queue or execute the same function over and over?
|
* @tparam queue should we use a queue or execute the same function over and over?
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit d88c5e15079047777b418132ece5879e7c9aaa2b
|
Subproject commit 8a889d3699b3c09ade435641fb034427f3fd12b6
|
Loading…
Reference in New Issue