一个等待外部notify他的线程池
cpp
class thread_pool_PDAC
{
private:
enum class worker_state
{
Idle,
TryFetch,
Work
};
enum class cu_state
{
Pending,
Ready,
Running
};
static const int MaxThreads = 16;
std::atomic_bool _is_running;
std::mutex _mutex;
std::condition_variable _cond;
std::condition_variable _finishedCond;
size_t _thread_no;
std::vector<std::thread> _threads;
std::function<void(int, int)> _workTask;
std::function<bool(int)> _checkTask;
bool _needCheck = false;
std::deque<int> _pendingCUs;
std::queue<int> _readyCUs;
std::unordered_map<int, cu_state> _cuStates;
std::atomic<int> activeNum{0};
public:
thread_pool_PDAC(const thread_pool_PDAC &tp) = delete;
thread_pool_PDAC &operator=(const thread_pool_PDAC &tp) = delete;
public:
thread_pool_PDAC(size_t no = 1) : _is_running(false), _thread_no(no)
{
if (_thread_no >= MaxThreads)
{
_thread_no = MaxThreads;
}
_workTask = [](int, int) {};
_checkTask = [](int) { return true; };
}
~thread_pool_PDAC()
{
if (_is_running)
{
stop();
}
}
private:
bool tryTakeReadyTaskLocked(int &cuIndex)
{
while (!_readyCUs.empty())
{
int candidate = _readyCUs.front();
_readyCUs.pop();
auto iter = _cuStates.find(candidate);
if (iter == _cuStates.end() || iter->second != cu_state::Ready)
{
continue;
}
iter->second = cu_state::Running;
cuIndex = candidate;
if (!_readyCUs.empty())
{
_cond.notify_one();
}
return true;
}
return false;
}
bool tryTakePendingCandidateLocked(int &cuIndex)
{
while (!_pendingCUs.empty())
{
int candidate = _pendingCUs.front();
_pendingCUs.pop_front();
auto iter = _cuStates.find(candidate);
if (iter == _cuStates.end() || iter->second != cu_state::Pending)
{
continue;
}
cuIndex = candidate;
return true;
}
_needCheck = false;
return false;
}
bool tryFetchReadyTask(int &cuIndex)
{
std::lock_guard<std::mutex> lock(_mutex);
return tryTakeReadyTaskLocked(cuIndex);
}
bool tryTakePendingCandidate(int &cuIndex)
{
std::lock_guard<std::mutex> lock(_mutex);
return tryTakePendingCandidateLocked(cuIndex);
}
bool promoteCheckedCandidate(int cuIndex)
{
std::lock_guard<std::mutex> lock(_mutex);
auto iter = _cuStates.find(cuIndex);
if (iter == _cuStates.end())
{
return false;
}
if (iter->second != cu_state::Pending)
{
return false;
}
iter->second = cu_state::Running;
return true;
}
void restorePendingCandidate(int cuIndex)
{
std::lock_guard<std::mutex> lock(_mutex);
auto iter = _cuStates.find(cuIndex);
if (iter == _cuStates.end() || iter->second != cu_state::Pending)
{
return;
}
_pendingCUs.push_back(cuIndex);
_needCheck = false;
}
void finishTask(int cuIndex)
{
std::lock_guard<std::mutex> lock(_mutex);
auto iter = _cuStates.find(cuIndex);
if (iter != _cuStates.end() && iter->second == cu_state::Running)
{
_cuStates.erase(iter);
}
_finishedCond.notify_all();
if (!_readyCUs.empty())
{
_cond.notify_one();
}
}
void work(int threadIndex)
{
worker_state state = worker_state::Idle;
int cuIndex = -1;
while (_is_running)
{
switch (state)
{
case worker_state::Idle: {
std::unique_lock<std::mutex> lock(_mutex);
_cond.wait(lock, [this]() { return !_is_running || !_readyCUs.empty() || _needCheck; });
if (!_is_running)
{
return;
}
state = worker_state::TryFetch;
break;
}
case worker_state::TryFetch: {
if (tryFetchReadyTask(cuIndex))
{
state = worker_state::Work;
break;
}
if (!tryTakePendingCandidate(cuIndex))
{
state = worker_state::Idle;
break;
}
bool isReady = _checkTask ? _checkTask(cuIndex) : false;
if (isReady && promoteCheckedCandidate(cuIndex))
{
state = worker_state::Work;
break;
}
restorePendingCandidate(cuIndex);
cuIndex = -1;
state = worker_state::Idle;
break;
}
case worker_state::Work: {
++activeNum;
_workTask(threadIndex, cuIndex);
--activeNum;
finishTask(cuIndex);
cuIndex = -1;
state = worker_state::TryFetch;
break;
}
}
}
}
public:
void setThreadNumber(size_t no)
{
if (no >= MaxThreads)
{
no = MaxThreads;
}
this->_thread_no = no;
}
void start()
{
this->_is_running = true;
{
std::lock_guard<std::mutex> lock(_mutex);
_needCheck = !_pendingCUs.empty();
}
for (size_t i = 0; i < _thread_no; i++)
{
_threads.emplace_back(std::thread(&thread_pool_PDAC::work, this, static_cast<int>(i)));
}
_cond.notify_all();
}
void stop()
{
{
std::lock_guard<std::mutex> lock(_mutex);
_is_running = false;
_needCheck = false;
}
_cond.notify_all();
for (std::thread &thd : _threads)
{
if (thd.joinable())
{
thd.join();
}
}
_threads.clear();
}
void setWorkTask(const std::function<void(int, int)> &t) { this->_workTask = t; }
void setFetchTask(const std::function<bool(int)> &t) { this->_checkTask = t; }
void EnqueueTask(int cuIndex)
{
if (!_is_running)
{
return;
}
std::lock_guard<std::mutex> lock(_mutex);
auto inserted = _cuStates.emplace(cuIndex, cu_state::Pending);
if (!inserted.second)
{
return;
}
_pendingCUs.push_back(cuIndex);
_needCheck = true;
_cond.notify_one();
_finishedCond.notify_all();
}
void notify(int cuIndex)
{
if (!_is_running)
{
return;
}
std::lock_guard<std::mutex> lock(_mutex);
auto iter = _cuStates.find(cuIndex);
if (iter == _cuStates.end())
{
// 外界 CU,错误
std::cerr << "[Error]: unregistered CU: " << cuIndex << std::endl;
return;
}
if (iter->second == cu_state::Pending)
{
iter->second = cu_state::Ready;
_readyCUs.push(cuIndex);
_cond.notify_one();
}
}
void waitFinished()
{
std::unique_lock<std::mutex> lock(_mutex);
_finishedCond.wait(lock, [this]() { return _cuStates.empty() && activeNum.load(std::memory_order_acquire) == 0; });
}
};