测试环境
lin@debian:~$ uname -a
Linux debian 6.1.0-23-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.99-1 (2024-07-15) x86_64 GNU/Linux
lin@debian:~$ g++ --version
g++ (Debian 12.2.0-14) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
C++标准
-std >= c++11
参考
爱编程的大丙 -> 异步线程池(基于C++11实现)
链接:
https://subingwen.cn/cpp/threadpool/
实现
头文件
ThreadPool.h
:
#ifndef INC_THREADPOOL_H
#define INC_THREADPOOL_H 1
#include <thread>
#include <functional>
namespace ThreadPool {
int Init(const int min_threads_nums, const int max_threads_nums);
int Destory();
int AddTask(std::function<void()> &&task);
template <typename Func, typename...Args>
inline int AddTask(Func &&func, Args&&...args) {
auto task = std::bind(std::forward<Func>(func), std::forward<Args>(args)...);
return AddTask(std::function<void()>(std::move(task)));
}
}
#endif
源文件
ThreadPool.cpp
:
#include <map>
#include <mutex>
#include <queue>
#include <atomic>
#include <condition_variable>
#include "ThreadPool.h"
class CThreadPoolMng {
private:
const int m_min_threads;
const int m_max_threads;
std::thread *m_manager;
std::map<std::thread::id, std::thread> m_workers;
std::vector<std::thread::id> m_ids;
std::atomic<bool> m_stop;
std::atomic<int> m_cur_threads;
std::atomic<int> m_idle_threads;
std::atomic<int> m_exit_nums;
std::queue<std::function<void()>> m_tasks;
std::mutex m_ids_mtx;
std::mutex m_queue_mtx;
std::condition_variable m_conditions;
private:
void worker_func() {
while (m_stop.load() != true || m_tasks.empty() != true) {
std::function<void()> task = nullptr;
{
std::unique_lock<std::mutex> lock(m_queue_mtx);
while (m_tasks.empty()) {
m_conditions.wait(lock);
if (m_exit_nums.load() > 0) {
std::lock_guard<std::mutex> lck(m_ids_mtx);
if (m_exit_nums.load() <= 0) {
continue;
}
m_exit_nums--;
m_ids.emplace_back(std::this_thread::get_id());
std::printf("destory thread...\n");
m_idle_threads--;
return;
}
if (m_tasks.empty() && m_stop.load()) {
std::printf("exit thread...\n");
m_idle_threads--;
return;
}
}
if (m_tasks.empty() != true) {
task = std::move(m_tasks.front());
m_tasks.pop();
}
}
if (task) {
m_idle_threads--;
task();
m_idle_threads++;
}
}
}
void manager_func() {
// 创建工作线程
for (int i = 0; i < m_min_threads; i++) {
std::thread t(&CThreadPoolMng::worker_func, this);
m_workers.insert(std::make_pair(t.get_id(), std::move(t)));
m_cur_threads++;
m_idle_threads++;
}
while (m_stop.load() != true || m_tasks.empty() != true) {
if (m_min_threads == m_max_threads) {
std::this_thread::sleep_for(std::chrono::seconds(10));
continue;
}
const int idle = m_idle_threads.load(); // 闲置线程
const int current = m_cur_threads.load(); // 当前线程
// 任务过多
if (0 == idle && current < m_max_threads && m_tasks.empty() != true) {
std::thread t(&CThreadPoolMng::worker_func, this);
m_workers.insert(std::make_pair(t.get_id(), std::move(t)));
std::printf("add thread...\n");
m_cur_threads++;
m_idle_threads++;
continue;
}
// 线程过多
const int delnum = ((current - m_min_threads) >= 5 ? 5 : (current - m_min_threads)); // 当线程池数过多时, 删除的线程数
const bool more_cond = (idle > current / 2 && current - delnum >= m_min_threads); // 线程是否过多判断条件
if (delnum <= 0 || more_cond != true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
continue;
}
m_exit_nums += delnum;
m_conditions.notify_all();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::lock_guard<std::mutex> lck(m_ids_mtx);
for (const auto &id : m_ids) {
auto it = m_workers.find(id);
if (m_workers.end() == it) {
continue;
}
if (it->second.joinable()) {
it->second.join();
}
m_workers.erase(it);
m_cur_threads--;
}
m_ids.clear();
std::this_thread::sleep_for(std::chrono::seconds(10));
continue;
}
// 销毁工作线程
for (auto &it : m_workers) {
std::thread &t = it.second;
if (t.joinable()) {
t.join();
}
}
}
public:
CThreadPoolMng(const int min_threads_nums, const int max_threads_nums) : m_min_threads(min_threads_nums), m_max_threads(max_threads_nums) {
m_stop = false;
m_idle_threads = m_cur_threads = m_exit_nums = 0;
m_manager = new std::thread(&CThreadPoolMng::manager_func, this);
}
~CThreadPoolMng() {
m_stop = true;
m_conditions.notify_all();
if (m_manager->joinable()) {
m_manager->join();
}
delete m_manager;
}
void add_task(std::function<void()> &&task) {
if (m_stop.load() == true) {
return;
}
else {
std::lock_guard<std::mutex> lock(m_queue_mtx);
m_tasks.emplace(std::move(task));
}
m_conditions.notify_all();
}
};
static std::mutex s_threadinit_lock;
static CThreadPoolMng *s_threadpoolmng = nullptr;
int ThreadPool::Init(const int min_threads_nums, const int max_threads_nums) {
if (min_threads_nums < 1 || max_threads_nums < min_threads_nums) {
return -1;
}
if (s_threadpoolmng != nullptr) {
return -2;
}
std::lock_guard<std::mutex> lock(s_threadinit_lock);
if (s_threadpoolmng != nullptr) {
return -3;
}
s_threadpoolmng = new CThreadPoolMng(min_threads_nums, max_threads_nums);
return 0;
}
int ThreadPool::Destory() {
if (nullptr == s_threadpoolmng) {
return -1;
}
std::lock_guard<std::mutex> lock(s_threadinit_lock);
if (nullptr == s_threadpoolmng) {
return -2;
}
delete s_threadpoolmng;
s_threadpoolmng = nullptr;
return 0;
}
int ThreadPool::AddTask(std::function<void()> &&task) {
if (nullptr == s_threadpoolmng) {
return -1;
}
s_threadpoolmng->add_task(std::move(task));
return 0;
}
demo
#include <cstdio>
#include <iostream>
#include "ThreadPool.h"
void calc(const int x, const int y) {
const int res = x + y;
std::printf("in %s::%d:: res = [%d].\n", __func__, __LINE__, res);
std::this_thread::sleep_for(std::chrono::seconds(10));
}
int test(const int i) {
std::printf("in %s::%d:: i = [%d].\n", __func__, __LINE__, i);
std::this_thread::sleep_for(std::chrono::seconds(10));
return 0;
}
int main() {
ThreadPool::Init(4, 100);
for (int i = 0; i < 100; i++) {
ThreadPool::AddTask(calc, i, i * 2);
}
for (int i = 0; i < 100; i++) {
ThreadPool::AddTask(test, i);
}
std::getchar(); // 测试通过管理者线程检测到工作线程过多时退出工作线程
ThreadPool::Destory();
std::getchar(); // 测试通过delete管理者线程时退出工作线程, 一般数量为min_thread_nums
return 0;
}