#include "agent_smith/detail/blocking_pool.hpp"
#include <algorithm>
namespace agent_smith::internal
{
BlockingPool::BlockingPool(std::size_t size)
{
const std::size_t worker_count = std::max<std::size_t>(size, 1);
workers_.reserve(worker_count);
for(std::size_t index = 0; index < worker_count; ++index)
{
workers_.emplace_back([this](std::stop_token stop) { worker(stop); });
}
}
BlockingPool::~BlockingPool()
{
std::queue<WorkItem> pending;
{
std::lock_guard lock(mutex_);
stopping_ = true;
pending.swap(pending_);
}
while(!pending.empty())
{
pending.front().cancel();
pending.pop();
}
condition_.notify_all();
}
bool BlockingPool::enqueue(WorkItem item)
{
{
std::lock_guard lock(mutex_);
if(stopping_)
{
return false;
}
pending_.push(std::move(item));
}
condition_.notify_one();
return true;
}
void BlockingPool::worker(std::stop_token stop)
{
while(!stop.stop_requested())
{
WorkItem item;
{
std::unique_lock lock(mutex_);
condition_.wait(lock,
[&]()
{
return stop.stop_requested() || stopping_ ||
!pending_.empty();
});
if(stop.stop_requested() || stopping_)
{
return;
}
item = std::move(pending_.front());
pending_.pop();
}
item.run();
}
}
} // namespace agent_smith::internal