#pragma once
|
#include <iostream>
|
#include <mutex>
|
#include <atomic>
|
#include <condition_variable>
|
#include <queue>
|
#include <string>
|
|
using namespace std;
|
|
template<typename Task, const size_t DEFAULT_THREAD_NUM, const size_t MAX_THREAD_NUM>
|
class ThreadPool
|
{
|
public:
|
ThreadPool() = delete;
|
ThreadPool(const ThreadPool&) = delete;
|
ThreadPool& operator=(const ThreadPool&) = delete;
|
ThreadPool(ThreadPool&&) = delete;
|
ThreadPool& operator=(ThreadPool&&) = delete;
|
|
explicit ThreadPool(uint32_t timeout) :m_timeout(timeout), m_needRun(true)
|
{
|
for (int i = 0; i < DEFAULT_THREAD_NUM; i++)
|
{
|
thread([this] { RunTask(); }).detach();
|
}
|
}
|
~ThreadPool() {
|
m_needRun = false;
|
while (m_runningThreadNum > 0)
|
{
|
m_needRunCondition.notify_all();
|
}
|
|
}
|
void Push(Task& task) {
|
PushTask(task);
|
if (m_runningThreadNum < MAX_THREAD_NUM && m_idleThreadNum == 0)
|
{
|
thread([this] { RunTask(); }).detach();
|
}
|
m_needRunCondition.notify_all();
|
}
|
private:
|
bool IsQueueEmpty() {
|
lock_guard<mutex> lg(m_mutex);
|
return m_taskQueue.empty();
|
}
|
bool GetTask(Task& task) {
|
lock_guard<mutex> lg(m_mutex);
|
if (m_taskQueue.empty())
|
{
|
return false;
|
}
|
task = m_taskQueue.top();
|
m_taskQueue.pop();
|
return true;
|
}
|
class NumWrapper
|
{
|
public:
|
NumWrapper() = delete;
|
NumWrapper(atomic<uint32_t>& num) :m_num(num) { m_num++; }
|
~NumWrapper() { m_num--; }
|
|
private:
|
atomic<uint32_t>& m_num;
|
};
|
|
void Sleep() {
|
mutex needRunMutex;
|
unique_lock<mutex> lock(needRunMutex);
|
|
NumWrapper idleWraper(m_idleThreadNum);
|
(void)idleWraper;
|
|
m_needRunCondition.wait_for(lock, std::chrono::seconds(m_timeout),
|
[this] { return !m_needRun || !IsQueueEmpty(); });
|
}
|
void PushTask(const Task& task) {
|
lock_guard<mutex> lg(m_mutex);
|
m_taskQueue.push(task);
|
}
|
void RunTask() {
|
NumWrapper runWraper(m_runningThreadNum);
|
(void)runWraper;
|
|
while (m_needRun)
|
{
|
Task task;
|
if (GetTask(task))
|
{
|
task.Execute();
|
continue;
|
}
|
Sleep();
|
|
if (!m_needRun)
|
{
|
return;
|
}
|
if (GetTask(task))
|
{
|
task.Execute();
|
continue;
|
}
|
if (m_runningThreadNum > DEFAULT_THREAD_NUM)
|
{
|
return;
|
}
|
}
|
}
|
|
private:
|
atomic<uint32_t> m_idleThreadNum;
|
atomic<uint32_t> m_runningThreadNum;
|
atomic_bool m_needRun;
|
|
mutex m_mutex;
|
condition_variable m_needRunCondition;
|
uint32_t m_timeout;
|
priority_queue<Task> m_taskQueue;
|
};
|
|
class Task
|
{
|
public:
|
Task() :m_priority(0) {};
|
explicit Task(string context) :m_priority(0) {
|
m_context = context;
|
}
|
|
bool operator<(const Task& t) const {
|
return m_priority < t.m_priority;
|
}
|
|
void Execute() {
|
lock_guard<mutex> lg(m_mutex);
|
cout << "Task is executed,name is" << m_context << endl;
|
}
|
|
public:
|
uint32_t m_priority;
|
private:
|
string m_context;
|
static mutex m_mutex;
|
};
|