스레드 풀은 작업이 대기열에 추가된 다음 스레드가 생성된 후 자동으로 시작되는 멀티스레딩의 한 형태입니다. 스레드 풀 스레드는 모두 백그라운드 스레드입니다. 각 스레드는 기본 스택 크기를 사용하고 기본 우선 순위로 실행되며 다중 스레드 아파트에 있습니다. 스레드가 관리 코드 에서 유휴 상태인 경우 (예: 이벤트 대기) 스레드 풀은 다른 작업자 스레드를 삽입하여 모든 프로세서를 바쁜 상태로 유지합니다. 모든 스레드 풀 스레드가 항상 사용 중이지만 대기열에 보류 중인 작업이 포함된 경우 스레드 풀은 잠시 후 다른 작업자 스레드를 생성하지만 스레드 수가 최대값을 초과하지 않습니다. 최대값을 초과하는 스레드는 대기열에 추가될 수 있지만 다른 스레드가 완료될 때까지 시작되지 않습니다.
C++11 표준은 스레드를 지원하지만 스레드 풀은 지원하지 않습니다. 이 기사에서는 C++11을 사용하여 우선순위 없이 가장 간단한 스레드 풀을 구현합니다.
C++ 11은 간단한 스레드 풀을 구현합니다.
C++11에 사용된 새로운 기능은 다음과 같습니다.
표준::unique_lock
표준::뮤텍스
표준::atomic_bool
표준::스레드
표준::미래
표준::조건_변수
표준::함수
표준::앞으로
표준::packaged_task
표준::make_shared
auto, decltype 자동 유형 공제
스레드로부터 안전한 큐
내부 개체에 액세스하기 위한 스레드 안전성을 보장하기 위해 std::queue<T>를 기반으로 구현되었습니다.
/**
* @brief 线程安全队列
* @author GGX
* @date 2023-08-13
*/
template <typename T>
class CSateQueue
{
public:
CSateQueue() = default;
~CSateQueue() {}
/**
* @brief 队列是否为空
* @param 无
* @return true 空,false 非空
* @author GGX
* @date 2023-08-19
*/
bool empty() const
{
std::unique_lock<std::mutex> lock(m_mutex);
return m_queue.empty();
}
/**
* @brief 队列是否为空
* @param 无
* @return size_t 队列大小
* @author GGX
* @date 2023-08-19
*/
size_t size() const
{
std::unique_lock<std::mutex> lock(m_mutex);
return m_queue.size();
}
/**
* @brief 压栈
* @param 对象
* @return 无
* @author GGX
* @date 2023-08-19
*/
void push(T &t)
{
std::unique_lock<std::mutex> lock(m_mutex);
m_queue.emplace(t);
}
/**
* @brief 出栈
* @param 对象
* @return true 成功,false 失败
* @author GGX
* @date 2023-08-19
*/
bool front(T &t)
{
std::unique_lock<std::mutex> lock(m_mutex);
if (m_queue.empty())
{
return false;
}
t = std::move(m_queue.front());
m_queue.pop();
return true;
}
private:
// 利用模板函数构造队列
std::queue<T> m_queue;
// 互斥量,可修改
mutable std::mutex m_mutex;
};
스레드 풀
영구 스레드, 작업이 있을 때만 스레드를 시작합니다.
/**
* @brief 线程池
* @author GGX
* @date 2023-08-13
*/
class ThreadPool
{
public:
/**
* @brief 构造函数,默认六个线程
* @param [in] size 线程数目
* @return
* @author GGX
* @date 2023-08-19
*/
explicit ThreadPool(size_t size = 6): m_size(size)
{
m_active = false;
}
~ThreadPool()
{
stop();
}
/**
* @brief 启动线程池
* @param 无
* @return 无
* @author GGX
* @date 2023-08-19
*/
void start()
{
//标记线程启动
m_active = true;
m_threads.reserve(m_size);
for (size_t i = 0; i < m_size; i++)
{
//创建线程池
m_threads.emplace_back(ThreadPool::work, this);
}
std::cout << "ThreadPool start" << std::endl;
}
/**
* @brief 停止线程池
* @param 无
* @return 无
* @author GGX
* @date 2023-08-19
*/
void stop()
{
//标记线程停止
m_active = false;
//唤醒所有线程
m_cv.notify_all();
for (thread &th : m_threads)
{
//优雅的退出线程
if (th.joinable())
{
th.join();
}
}
std::cout << "ThreadPool stop" << std::endl;
}
void work()
{
std::function<void()> func; // 定义基础函数类func
bool dequeued = false; // 是否正在取出队列中元素
while (m_active)
{
dequeued = false;
{
std::unique_lock<std::mutex> lock(m_mutex);
//判断任务队列是否为空,线程是否已停止
auto funcR = [](CSateQueue<std::function<void()>> &tasks,
std::atomic_bool & bActive)->bool
{
return !tasks.empty() || !bActive;
};
//等待线程被唤醒
m_cv.wait(lock, std::bind(funcR, std::ref(m_tasks), std::ref(m_active)));
if (!m_active)
{
break;
}
dequeued = m_tasks.front(func);
}
//取到任务,则运行
if (dequeued)
{
func();
}
}
}
/**
* @brief 提交任务,让线程执行
* @param [in] f 任务
* @param [in] ...args 可变参
* @return auto 返回值类型,自动推导
* @author GGX
* @date 2023-08-19
*/
template <typename F, typename ...Args>
auto submit(F && f, Args && ...args)->std::future<decltype(f(args...))>
{
//返回值类型
using returnType = decltype(f(args...))();
//函数包
std::function<returnType> func =
std::bind(std::forward<F>(f), std::forward<Args>(args)...);
//包装任何可调用函数对象
auto fu_ptr = std::make_shared<std::packaged_task<returnType>> (func);
std::function<void()> task = [fu_ptr]
{
(*fu_ptr)();
};
//函数放入队列
m_tasks.push(task);
//唤醒一个线程
m_cv.notify_one();
//返回结果
return fu_ptr->get_future();
}
private:
size_t m_size; //线程大小
std::atomic_bool m_active; //线程是否运行,原子变量
vector<thread> m_threads; //线程容器
std::condition_variable m_cv;//条件变量,唤醒线程
std::mutex m_mutex; //互斥量,保证线程安全
CSateQueue<std::function<void()>> m_tasks; //任务队列
};
통화 예
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <vector>
#include <queue>
#include <functional>
#include <future>
#include <random>
using namespace std;
/**
* @brief 线程安全队列
* @author GGX
* @date 2023-08-13
*/
template <typename T>
class CSateQueue
{
public:
CSateQueue() = default;
~CSateQueue() {}
/**
* @brief 队列是否为空
* @param 无
* @return true 空,false 非空
* @author GGX
* @date 2023-08-19
*/
bool empty() const
{
std::unique_lock<std::mutex> lock(m_mutex);
return m_queue.empty();
}
/**
* @brief 队列是否为空
* @param 无
* @return size_t 队列大小
* @author GGX
* @date 2023-08-19
*/
size_t size() const
{
std::unique_lock<std::mutex> lock(m_mutex);
return m_queue.size();
}
/**
* @brief 压栈
* @param 对象
* @return 无
* @author GGX
* @date 2023-08-19
*/
void push(T &t)
{
std::unique_lock<std::mutex> lock(m_mutex);
m_queue.emplace(t);
}
/**
* @brief 出栈
* @param 对象
* @return true 成功,false 失败
* @author GGX
* @date 2023-08-19
*/
bool front(T &t)
{
std::unique_lock<std::mutex> lock(m_mutex);
if (m_queue.empty())
{
return false;
}
t = std::move(m_queue.front());
m_queue.pop();
return true;
}
private:
// 利用模板函数构造队列
std::queue<T> m_queue;
// 互斥量,可修改
mutable std::mutex m_mutex;
};
/**
* @brief 线程池
* @author GGX
* @date 2023-08-13
*/
class ThreadPool
{
public:
/**
* @brief 构造函数,默认六个线程
* @param [in] size 线程数目
* @return
* @author GGX
* @date 2023-08-19
*/
explicit ThreadPool(size_t size = 6): m_size(size)
{
m_active = false;
}
~ThreadPool()
{
stop();
}
/**
* @brief 启动线程池
* @param 无
* @return 无
* @author GGX
* @date 2023-08-19
*/
void start()
{
//标记线程启动
m_active = true;
m_threads.reserve(m_size);
for (size_t i = 0; i < m_size; i++)
{
//创建线程池
m_threads.emplace_back(ThreadPool::work, this);
}
std::cout << "ThreadPool start" << std::endl;
}
/**
* @brief 停止线程池
* @param 无
* @return 无
* @author GGX
* @date 2023-08-19
*/
void stop()
{
//标记线程停止
m_active = false;
//唤醒所有线程
m_cv.notify_all();
for (thread &th : m_threads)
{
//优雅的退出线程
if (th.joinable())
{
th.join();
}
}
std::cout << "ThreadPool stop" << std::endl;
}
void work()
{
std::function<void()> func; // 定义基础函数类func
bool dequeued = false; // 是否正在取出队列中元素
while (m_active)
{
dequeued = false;
{
std::unique_lock<std::mutex> lock(m_mutex);
//判断任务队列是否为空,线程是否已停止
auto funcR = [](CSateQueue<std::function<void()>> &tasks,
std::atomic_bool & bActive)->bool
{
return !tasks.empty() || !bActive;
};
//等待线程被唤醒
m_cv.wait(lock, std::bind(funcR, std::ref(m_tasks), std::ref(m_active)));
if (!m_active)
{
break;
}
dequeued = m_tasks.front(func);
}
//取到任务,则运行
if (dequeued)
{
func();
}
}
}
/**
* @brief 提交任务,让线程执行
* @param [in] f 任务
* @param [in] ...args 可变参
* @return auto 返回值类型,自动推导
* @author GGX
* @date 2023-08-19
*/
template <typename F, typename ...Args>
auto submit(F && f, Args && ...args)->std::future<decltype(f(args...))>
{
//返回值类型
using returnType = decltype(f(args...))();
//函数包
std::function<returnType> func =
std::bind(std::forward<F>(f), std::forward<Args>(args)...);
//包装任何可调用函数对象
auto fu_ptr = std::make_shared<std::packaged_task<returnType>> (func);
std::function<void()> task = [fu_ptr]
{
(*fu_ptr)();
};
//函数放入队列
m_tasks.push(task);
//唤醒一个线程
m_cv.notify_one();
//返回结果
return fu_ptr->get_future();
}
private:
size_t m_size; //线程大小
std::atomic_bool m_active; //线程是否运行,原子变量
vector<thread> m_threads; //线程容器
std::condition_variable m_cv;//条件变量,唤醒线程
std::mutex m_mutex; //互斥量,保证线程安全
CSateQueue<std::function<void()>> m_tasks; //任务队列
};
std::random_device rd; // 真实随机数产生器
std::mt19937 mt(rd()); //生成计算随机数mt
std::uniform_int_distribution<int> dist(-1000, 1000); //生成-1000到1000之间的离散均匀分布数
auto rnd = std::bind(dist, mt);
/**
* @brief 测试线程池
* @author GGX
* @date 2023-08-13
*/
class CTest
{
public:
void simulate_hard_computation()
{
std::this_thread::sleep_for(std::chrono::milliseconds(2000 + rnd()));
}
void multiply(const int a, const int b)
{
simulate_hard_computation();
const int res = a * b;
std::cout << "multiply thid: " << std::this_thread::get_id() << std::endl;
std::cout << a << " * " << b << " = " << res << std::endl;
}
void multiply_output(int &out, const int a, const int b)
{
simulate_hard_computation();
out = a * b;
std::cout << "multiply_output thid: " << std::this_thread::get_id() << std::endl;
std::cout << a << " * " << b << " = " << out << std::endl;
}
int multiply_return(const int a, const int b)
{
simulate_hard_computation();
const int res = a * b;
std::cout << "multiply_return thid: " << std::this_thread::get_id() << std::endl;
std::cout << a << " * " << b << " = " << res << std::endl;
return res;
}
};
void example()
{
CTest a;
ThreadPool pool(6);
pool.start();
//对象方法,因此需要绑定对象
std::function<void(int, int)> multiply =
std::bind(&CTest::multiply, &a, std::placeholders::_1, std::placeholders::_2);
for (int i = 1; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
//提交调用
pool.submit(multiply, i, j);
}
}
auto future = pool.submit(multiply, 3, 10);
future.get();
int output_ref;
std::function<void(int&, int, int)> multiply_output =
std::bind(&CTest::multiply_output, &a, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3);
// 使用ref传递的输出参数提交函数
auto future1 = pool.submit(multiply_output, std::ref(output_ref), 5, 6);
future1.get();
std::cout << "Last operation result is equals to " << output_ref << std::endl;
// 使用return参数提交函数
std::function<int(int, int)> multiply_return =
std::bind(&CTest::multiply_return, &a, std::placeholders::_1, std::placeholders::_2);
auto future2 = pool.submit(multiply_return, 5, 3);
// 等待乘法输出完成
int res = future2.get();
std::cout << "Last operation result is equals to " << res << std::endl;
pool.stop();
}
int main()
{
std::cout << "std::thread::hardware_concurrency() "
<< std::thread::hardware_concurrency() << std::endl << std::endl;
example();
return 0;
}
산출