【Linux】线程池封装与介绍

server/2025/2/6 1:20:56/
🔥 个人主页:大耳朵土土垚
🔥 所属专栏:Linux系统编程

这里将会不定期更新有关Linux的内容,欢迎大家点赞,收藏,评论🥳🥳🎉🎉🎉

文章目录

  • 1. 线程池介绍
  • 2. 线程池封装
    • 完整实现
  • 3. 线程安全的单例模式
    • 单例模式的特点
    • 饿汉实现方式和懒汉实现方式
  • 4. 单例式线程池
    • 完整实现

1. 线程池介绍

  之前我们实现了线程、互斥量、条件变量以及日志的封装,现在我们可以基于以上内容来封装一个线程池。

  线程池是一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。

  线程池的应用场景:

  • 需要大量的线程来完成任务,且完成任务的时间比较短。 比如WEB服务器完成网页请求这样的任务,使用线程池技术是非常合适的。因为单个任务小,而任务数量巨大,你可以想象⼀个热门网站的点击次数。 但对于长时间的任务,比如⼀个Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。

  • 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。

  • 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限,出现错误。

  线程池的种类:

  • 创建固定数量线程池,循环从任务队列中获取任务对象,获取到任务对象后,执行任务对象中的任务接口;
  • 浮动线程池,其他同上。

此处,我们选择固定线程个数的线程池。

在这里插入图片描述

2. 线程池封装

  • 首先我们需要包含需要的头文件以及命名空间,线程池类中成员变量需要一把锁、条件变量、条件变量下等待的线程个数、存放线程的数组、线程总个数、存放任务的任务队列以及线程池是否在运行的状态表示:

#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <memory>
#include "Log.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Thread.hpp"
namespace ThreadPoolModule
{using namespace LogModule;using namespace MutexModule;using namespace CondModule;using namespace ThreadModule;using thread_t = std::shared_ptr<Thread>;const static int gthreadnum = 10;template <typename T>class ThreadPool{private:int _threadnum; // 线程个数Mutex _mutex;Cond _cond;int _waitnum;std::vector<thread_t> _threads; // 存放线程std::queue<T> _tasks;           // 任务队列bool _isrunning;};
}

因为任务种类的不确定性,所以我们需要使用模板

  • 在线程池类的构造函数中我们就可以创建固定数量的线程并给每个线程绑定执行的方法:
template <typename T>class ThreadPool{private:bool IsEmpty() { return _tasks.empty(); }void HandlerTask(std::string name){LOG(LogLevel::INFO) << name << " HandlerTask...";T task;while (true){{LockGuard lockguard(_mutex);while (IsEmpty() && _isrunning){++_waitnum;_cond.Wait(_mutex);--_waitnum;}if(!_isrunning&&IsEmpty())//为了在退出之前处理完所有的任务break;task = _tasks.front();_tasks.pop();}//处理任务不需要加锁保护task(name);LOG(LogLevel::INFO) << name << " handled a task successfully...";}LOG(LogLevel::INFO) << name << " exit success...";}public:// 是要有的,必须是私有的ThreadPool(int threadnum = gthreadnum) : _threadnum(threadnum),_waitnum(0),_isrunning(false){// 创建线程for (int i = 0; i < _threadnum; i++){_threads.emplace_back(std::make_shared<Thread>(std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1))); // HandlerTask是成员函数有this参数,所以不能直接传参需要绑定LOG(LogLevel::INFO) << _threads.back()->Name() << "Create Success...";}LOG(LogLevel::INFO) << "ThreadPool Construct...";}~ThreadPool(){}private:int _threadnum; // 线程个数Mutex _mutex;Cond _cond;int _waitnum;std::vector<thread_t> _threads; // 存放线程std::queue<T> _tasks;           // 任务队列bool _isrunning;};
}

如果不清楚线程类中函数与线程池中的函数接口之间是怎么相互调用的可以看看:
在这里插入图片描述

  • 线程Start、Stop与Wait:
        void Start(){if (_isrunning)return;_isrunning = true;for (auto &thread : _threads){thread->Start();LOG(LogLevel::INFO) << thread->Name() << " Start Success...";}}void Stop(){LockGuard lockguard(_mutex);if(_isrunning){// 3. 不能在入任务了_isrunning = false; // 不工作// 1. 让线程自己退出(要唤醒) && // 2. 历史的任务被处理完了if(_waitnum>0)_cond.NotifyAll();}}void Wait(){for (auto &thread : _threads){thread->Join();LOG(LogLevel::INFO) << thread->Name() << "Wait Success...";}}

注意在线程池Stop这里,我们不能直接让线程退出,需要将线程池任务队列中所有任务处理完成后才能退出,所以我们可以借助条件变量唤醒所有等待的线程让它们去处理任务,等任务处理完成它们也就会随着函数执行完成后退出;然后就可以进行线程等待。

  • 线程池处理任务在上述HandlerTask中,我们还需要线程池插入新任务的方法:
bool Enqueue(const T &in){// 插入任务LockGuard lockguard(_mutex);if (!_isrunning)return false;_tasks.push(in);if (_waitnum > 0)_cond.Notify();return true;}

插入任务与处理任务一样访问了共享资源,所以需要加锁保护

完整实现

#pragma once#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <memory>
#include "Log.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Thread.hpp"
namespace ThreadPoolModule
{using namespace LogModule;using namespace MutexModule;using namespace CondModule;using namespace ThreadModule;using thread_t = std::shared_ptr<Thread>;const static int gthreadnum = 10;template <typename T>class ThreadPool{private:bool IsEmpty() { return _tasks.empty(); }void HandlerTask(std::string name){LOG(LogLevel::INFO) << name << " HandlerTask...";T task;while (true){{LockGuard lockguard(_mutex);while (IsEmpty() && _isrunning){++_waitnum;_cond.Wait(_mutex);--_waitnum;}if(!_isrunning&&IsEmpty())break;task = _tasks.front();_tasks.pop();}//处理任务不需要加锁保护task(name);LOG(LogLevel::INFO) << name << " handled a task successfully...";}LOG(LogLevel::INFO) << name << " exit success...";}public:// 是要有的,必须是私有的ThreadPool(int threadnum = gthreadnum) : _threadnum(threadnum),_waitnum(0),_isrunning(false){// 创建线程for (int i = 0; i < _threadnum; i++){_threads.emplace_back(std::make_shared<Thread>(std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1))); // HandlerTask是成员函数有this参数,所以不能直接传参需要绑定LOG(LogLevel::INFO) << _threads.back()->Name() << "Create Success...";}LOG(LogLevel::INFO) << "ThreadPool Construct...";}void Start(){if (_isrunning)return;_isrunning = true;for (auto &thread : _threads){thread->Start();LOG(LogLevel::INFO) << thread->Name() << " Start Success...";}}void Stop(){LockGuard lockguard(_mutex);if(_isrunning){// 3. 不能在入任务了_isrunning = false; // 不工作// 1. 让线程自己退出(要唤醒) && // 2. 历史的任务被处理完了if(_waitnum>0)_cond.NotifyAll();}}void Wait(){for (auto &thread : _threads){thread->Join();LOG(LogLevel::INFO) << thread->Name() << "Wait Success...";}}bool Enqueue(const T &in){// 插入任务LockGuard lockguard(_mutex);if (!_isrunning)return false;_tasks.push(in);if (_waitnum > 0)_cond.Notify();return true;}~ThreadPool(){}private:int _threadnum; // 线程个数Mutex _mutex;Cond _cond;int _waitnum;std::vector<thread_t> _threads; // 存放线程std::queue<T> _tasks;           // 任务队列bool _isrunning;};
}
  • 测试函数如下:

任务函数:

#pragma once#include <iostream>
#include <string>
#include <functional>
#include "Log.hpp"using namespace LogModule;using task_t = std::function<void(std::string name)>;void Push(std::string name)
{LOG(LogLevel::DEBUG) << "我是一个推送数据到服务器的一个任务, 我正在被执行" << "[" << name << "]";
}

main函数:

#include "ThreadPool.hpp"
#include"Task.hpp"
using namespace ThreadPoolModule;int main()
{ENABLE_CONSOLE_LOG_STRATEGY();// ENABLE_FILE_LOG_STRATEGY();std::unique_ptr<ThreadPool<task_t>> tp = std::make_unique<ThreadPool<task_t>>();tp->Start();int cnt = 10;char c;while (cnt){tp->Enqueue(Push);cnt--;sleep(1);}tp->Stop();sleep(3);tp->Wait();return 0;
}
  • 结果如下:
./thread_pool 
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [68] - Thread-1Create Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [68] - Thread-2Create Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [68] - Thread-3Create Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [68] - Thread-4Create Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [68] - Thread-5Create Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [68] - Thread-6Create Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [68] - Thread-7Create Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [68] - Thread-8Create Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [68] - Thread-9Create Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [68] - Thread-10Create Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [70] - ThreadPool Construct...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [81] - Thread-1 Start Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [81] - Thread-2 Start Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [81] - Thread-3 Start Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [81] - Thread-4 Start Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [81] - Thread-5 Start Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [81] - Thread-6 Start Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [81] - Thread-7 Start Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [81] - Thread-8 Start Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [81] - Thread-9 Start Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [81] - Thread-10 Start Success...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [30] - Thread-7 HandlerTask...
[2025-02-04 09:54:51 ][DEBUG] [2360325] [Task.hpp] [14] - 我是一个推送数据到服务器的一个任务, 我正在被执行[Thread-7]
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [51] - Thread-7 handled a task successfully...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [30] - Thread-8 HandlerTask...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [30] - Thread-9 HandlerTask...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [30] - Thread-6 HandlerTask...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [30] - Thread-10 HandlerTask...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [30] - Thread-5 HandlerTask...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [30] - Thread-4 HandlerTask...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [30] - Thread-3 HandlerTask...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [30] - Thread-2 HandlerTask...
[2025-02-04 09:54:51 ][INFO] [2360325] [ThreadPool.hpp] [30] - Thread-1 HandlerTask...
[2025-02-04 09:54:52 ][DEBUG] [2360325] [Task.hpp] [14] - 我是一个推送数据到服务器的一个任务, 我正在被执行[Thread-7]
[2025-02-04 09:54:52 ][INFO] [2360325] [ThreadPool.hpp] [51] - Thread-7 handled a task successfully...
[2025-02-04 09:54:53 ][DEBUG] [2360325] [Task.hpp] [14] - 我是一个推送数据到服务器的一个任务, 我正在被执行[Thread-8]
[2025-02-04 09:54:53 ][INFO] [2360325] [ThreadPool.hpp] [51] - Thread-8 handled a task successfully...
[2025-02-04 09:54:54 ][DEBUG] [2360325] [Task.hpp] [14] - 我是一个推送数据到服务器的一个任务, 我正在被执行[Thread-9]
[2025-02-04 09:54:54 ][INFO] [2360325] [ThreadPool.hpp] [51] - Thread-9 handled a task successfully...
[2025-02-04 09:54:55 ][DEBUG] [2360325] [Task.hpp] [14] - 我是一个推送数据到服务器的一个任务, 我正在被执行[Thread-6]
[2025-02-04 09:54:55 ][INFO] [2360325] [ThreadPool.hpp] [51] - Thread-6 handled a task successfully...
[2025-02-04 09:54:56 ][DEBUG] [2360325] [Task.hpp] [14] - 我是一个推送数据到服务器的一个任务, 我正在被执行[Thread-10]
[2025-02-04 09:54:56 ][INFO] [2360325] [ThreadPool.hpp] [51] - Thread-10 handled a task successfully...
[2025-02-04 09:54:57 ][DEBUG] [2360325] [Task.hpp] [14] - 我是一个推送数据到服务器的一个任务, 我正在被执行[Thread-5]
[2025-02-04 09:54:57 ][INFO] [2360325] [ThreadPool.hpp] [51] - Thread-5 handled a task successfully...
[2025-02-04 09:54:58 ][DEBUG] [2360325] [Task.hpp] [14] - 我是一个推送数据到服务器的一个任务, 我正在被执行[Thread-4]
[2025-02-04 09:54:58 ][INFO] [2360325] [ThreadPool.hpp] [51] - Thread-4 handled a task successfully...
[2025-02-04 09:54:59 ][DEBUG] [2360325] [Task.hpp] [14] - 我是一个推送数据到服务器的一个任务, 我正在被执行[Thread-3]
[2025-02-04 09:54:59 ][INFO] [2360325] [ThreadPool.hpp] [51] - Thread-3 handled a task successfully...
[2025-02-04 09:55:00 ][DEBUG] [2360325] [Task.hpp] [14] - 我是一个推送数据到服务器的一个任务, 我正在被执行[Thread-2]
[2025-02-04 09:55:00 ][INFO] [2360325] [ThreadPool.hpp] [51] - Thread-2 handled a task successfully...
[2025-02-04 09:55:01 ][INFO] [2360325] [ThreadPool.hpp] [54] - Thread-7 exit success...
[2025-02-04 09:55:01 ][INFO] [2360325] [ThreadPool.hpp] [54] - Thread-8 exit success...
[2025-02-04 09:55:01 ][INFO] [2360325] [ThreadPool.hpp] [54] - Thread-9 exit success...
[2025-02-04 09:55:01 ][INFO] [2360325] [ThreadPool.hpp] [54] - Thread-6 exit success...
[2025-02-04 09:55:01 ][INFO] [2360325] [ThreadPool.hpp] [54] - Thread-10 exit success...
[2025-02-04 09:55:01 ][INFO] [2360325] [ThreadPool.hpp] [54] - Thread-5 exit success...
[2025-02-04 09:55:01 ][INFO] [2360325] [ThreadPool.hpp] [54] - Thread-4 exit success...
[2025-02-04 09:55:01 ][INFO] [2360325] [ThreadPool.hpp] [54] - Thread-3 exit success...
[2025-02-04 09:55:01 ][INFO] [2360325] [ThreadPool.hpp] [54] - Thread-2 exit success...
[2025-02-04 09:55:01 ][INFO] [2360325] [ThreadPool.hpp] [54] - Thread-1 exit success...
[2025-02-04 09:55:04 ][INFO] [2360325] [ThreadPool.hpp] [101] - Thread-1Wait Success...
[2025-02-04 09:55:04 ][INFO] [2360325] [ThreadPool.hpp] [101] - Thread-2Wait Success...
[2025-02-04 09:55:04 ][INFO] [2360325] [ThreadPool.hpp] [101] - Thread-3Wait Success...
[2025-02-04 09:55:04 ][INFO] [2360325] [ThreadPool.hpp] [101] - Thread-4Wait Success...
[2025-02-04 09:55:04 ][INFO] [2360325] [ThreadPool.hpp] [101] - Thread-5Wait Success...
[2025-02-04 09:55:04 ][INFO] [2360325] [ThreadPool.hpp] [101] - Thread-6Wait Success...
[2025-02-04 09:55:04 ][INFO] [2360325] [ThreadPool.hpp] [101] - Thread-7Wait Success...
[2025-02-04 09:55:04 ][INFO] [2360325] [ThreadPool.hpp] [101] - Thread-8Wait Success...
[2025-02-04 09:55:04 ][INFO] [2360325] [ThreadPool.hpp] [101] - Thread-9Wait Success...
[2025-02-04 09:55:04 ][INFO] [2360325] [ThreadPool.hpp] [101] - Thread-10Wait Success...

3. 线程安全的单例模式

单例模式的特点

  某些类, 只应该具有⼀个对象(实例), 就称之为单例。

例如⼀个男⼈只能有⼀个媳妇。

  在很多服务器开发场景中, 经常需要让服务器加载很多的数据 (上百G) 到内存中. 此时往往要用一个单例的类来管理这些数据。

饿汉实现方式和懒汉实现方式

[洗碗的例子]

  • 吃完饭, 立刻洗碗, 这种就是饿汉方式. 因为下一顿吃的时候可以立刻拿着碗就能吃饭.
  • 吃完饭, 先把碗放下, 然后下⼀顿饭用到这个碗了再洗碗, 就是懒汉方式.

懒汉方式最核心的思想是 “延时加载”. 从而能够优化服务器的启动速度.

  • 饿汉方式实现单例模式:
template <typename T>
class Singleton {static T data;
public:static T* GetInstance() {return &data;}
};

只要通过 Singleton 这个包装类来使用 T 对象, 则⼀个进程中只有⼀个 T 对象的实例.

  • 懒汉方式实现单例模式:
template <typename T>
class Singleton {static T* inst;public:static T* GetInstance() {if (inst == NULL){inst = new T();}return inst;}
};

这种方式存在⼀个严重的问题, 线程不安全。第一次调用 GetInstance 的时候, 如果两个线程同时调用, 可能会创建出两份 T 对象的实例。但是后续再次调用, 就没有问题了。与之前未加锁的简易抢票示例相似。

  • 懒汉方式实现单例模式(线程安全版本):
// 懒汉模式, 线程安全
template <typename T>
class Singleton {volatile static T* inst; // 需要设置 volatile 关键字, 否则可能被编译器优化.static std::mutex lock;
public:static T* GetInstance() {if (inst == NULL) // 双重判定空指针, 降低锁冲突的概率, 提⾼性能.{ lock.lock(); // 使⽤互斥锁, 保证多线程情况下也只调⽤⼀次 new.if (inst == NULL) {inst = new T();}lock.unlock();}return inst;}
};

注意事项:

  1. 加锁解锁的位置
  2. 双重 if 判定, 避免不必要的锁竞争

如果inst不是NULL就没必要加锁

  1. volatile关键字防止过度优化

4. 单例式线程池

  我们使用的是饿汉实现方式来实现单例线程池,首先我们需要创建静态全局的线程池指针以及锁:

#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <memory>
#include "Log.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Thread.hpp"
namespace ThreadPoolModule
{using namespace LogModule;using namespace MutexModule;using namespace CondModule;using namespace ThreadModule;using thread_t = std::shared_ptr<Thread>;const static int gthreadnum = 10;template <typename T>class ThreadPool{private:int _threadnum; // 线程个数Mutex _mutex;Cond _cond;int _waitnum;std::vector<thread_t> _threads; // 存放线程std::queue<T> _tasks;           // 任务队列bool _isrunning;// 添加单例模式static ThreadPool<T> *_instance;static Mutex _lock;
};
//在类外初始化
template <typename T>
ThreadPool<T> *ThreadPool<T>::_instance = nullptr;
template <typename T>
Mutex ThreadPool<T>::_lock;
}
  • 然后获取线程池单例函数:
static ThreadPool<T> *GetInstance(){if (_instance == nullptr){LockGuard lockguard(_lock);if (_instance == nullptr){_instance = new ThreadPool<T>();_instance->Start();}}LOG(LogLevel::DEBUG) << "GetInstance success...";return _instance;}
  • 最后将构造函数以及Start函数设为私有以及将赋值和拷贝构造禁用。

完整实现

#pragma once#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <memory>
#include "Log.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Thread.hpp"
namespace ThreadPoolModule
{using namespace LogModule;using namespace MutexModule;using namespace CondModule;using namespace ThreadModule;using thread_t = std::shared_ptr<Thread>;const static int gthreadnum = 10;template <typename T>class ThreadPool{private:// 是要有的,必须是私有的ThreadPool(int threadnum = gthreadnum) : _threadnum(threadnum),_waitnum(0),_isrunning(false){// 创建线程for (int i = 0; i < _threadnum; i++){_threads.emplace_back(std::make_shared<Thread>(std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1))); // HandlerTask是成员函数有this参数,所以不能直接传参需要绑定LOG(LogLevel::INFO) << _threads.back()->Name() << "Create Success...";}LOG(LogLevel::INFO) << "ThreadPool Construct...";}bool IsEmpty() { return _tasks.empty(); }void HandlerTask(std::string name){LOG(LogLevel::INFO) << name << " HandlerTask...";T task;while (true){{LockGuard lockguard(_mutex);while (IsEmpty() && _isrunning){++_waitnum;_cond.Wait(_mutex);--_waitnum;}if (!_isrunning && IsEmpty())break;task = _tasks.front();_tasks.pop();}// 处理任务不需要加锁保护task(name);LOG(LogLevel::INFO) << name << " handled a task successfully...";}LOG(LogLevel::INFO) << name << " exit success...";}void Start(){if (_isrunning)return;_isrunning = true;for (auto &thread : _threads){thread->Start();LOG(LogLevel::INFO) << thread->Name() << " Start Success...";}}// 赋值、拷⻉禁⽤ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;ThreadPool(const ThreadPool<T> &) = delete;public:static ThreadPool<T> *GetInstance(){if (_instance == nullptr){LockGuard lockguard(_lock);if (_instance == nullptr){_instance = new ThreadPool<T>();_instance->Start();}}LOG(LogLevel::DEBUG) << "GetInstance success...";return _instance;}void Stop(){LockGuard lockguard(_mutex);if (_isrunning){// 3. 不能在入任务了_isrunning = false; // 不工作// 1. 让线程自己退出(要唤醒) && // 2. 历史的任务被处理完了if (_waitnum > 0)_cond.NotifyAll();}}void Wait(){for (auto &thread : _threads){thread->Join();LOG(LogLevel::INFO) << thread->Name() << "Wait Success...";}}bool Enqueue(const T &in){// 插入任务LockGuard lockguard(_mutex);if (!_isrunning)return false;_tasks.push(in);if (_waitnum > 0)_cond.Notify();return true;}~ThreadPool(){}private:int _threadnum; // 线程个数Mutex _mutex;Cond _cond;int _waitnum;std::vector<thread_t> _threads; // 存放线程std::queue<T> _tasks;           // 任务队列bool _isrunning;// 单例模式static ThreadPool<T> *_instance;static Mutex _lock;};// 在类外初始化template <typename T>ThreadPool<T> *ThreadPool<T>::_instance = nullptr;template <typename T>Mutex ThreadPool<T>::_lock;
}
  • 测试函数:
#include <iostream>
#include <functional>
#include <unistd.h>
#include "ThreadPool.hpp"
using namespace ThreadPoolModule;using task_t = std::function<void(std::string name)>;
void DownLoad(std::string name)
{std::cout << "this is a task" << std::endl;
}
int main()
{ENABLE_CONSOLE_LOG_STRATEGY();int cnt = 10;while (cnt){ThreadPool<task_t>::GetInstance()->Enqueue(DownLoad);sleep(1);cnt--;}ThreadPool<task_t>::GetInstance()->Stop();sleep(5);ThreadPool<task_t>::GetInstance()->Wait();return 0;
}
  • 结果如下:
tutu@hecs-16648:~/linux/ThreadPool$ ./thread_pool 
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [36] - Thread-1Create Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [36] - Thread-2Create Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [36] - Thread-3Create Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [36] - Thread-4Create Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [36] - Thread-5Create Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [36] - Thread-6Create Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [36] - Thread-7Create Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [36] - Thread-8Create Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [36] - Thread-9Create Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [36] - Thread-10Create Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [38] - ThreadPool Construct...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [76] - Thread-1 Start Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [76] - Thread-2 Start Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [76] - Thread-3 Start Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [76] - Thread-4 Start Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [76] - Thread-5 Start Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [76] - Thread-6 Start Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [76] - Thread-7 Start Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [76] - Thread-8 Start Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [76] - Thread-9 Start Success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [76] - Thread-10 Start Success...
[2025-02-04 14:40:58 ][DEBUG] [2368011] [ThreadPool.hpp] [95] - GetInstance success...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [43] - Thread-7 HandlerTask...
this is a task
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [43] - Thread-8 HandlerTask...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [64] - Thread-7 handled a task successfully...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [43] - Thread-6 HandlerTask...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [43] - Thread-9 HandlerTask...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [43] - Thread-10 HandlerTask...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [43] - Thread-5 HandlerTask...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [43] - Thread-4 HandlerTask...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [43] - Thread-3 HandlerTask...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [43] - Thread-2 HandlerTask...
[2025-02-04 14:40:58 ][INFO] [2368011] [ThreadPool.hpp] [43] - Thread-1 HandlerTask...
[2025-02-04 14:40:59 ][DEBUG] [2368011] [ThreadPool.hpp] [95] - GetInstance success...
this is a task
[2025-02-04 14:40:59 ][INFO] [2368011] [ThreadPool.hpp] [64] - Thread-8 handled a task successfully...
[2025-02-04 14:41:00 ][DEBUG] [2368011] [ThreadPool.hpp] [95] - GetInstance success...
this is a task
[2025-02-04 14:41:00 ][INFO] [2368011] [ThreadPool.hpp] [64] - Thread-7 handled a task successfully...
[2025-02-04 14:41:01 ][DEBUG] [2368011] [ThreadPool.hpp] [95] - GetInstance success...
this is a task
[2025-02-04 14:41:01 ][INFO] [2368011] [ThreadPool.hpp] [64] - Thread-6 handled a task successfully...
[2025-02-04 14:41:02 ][DEBUG] [2368011] [ThreadPool.hpp] [95] - GetInstance success...
this is a task
[2025-02-04 14:41:02 ][INFO] [2368011] [ThreadPool.hpp] [64] - Thread-9 handled a task successfully...
[2025-02-04 14:41:03 ][DEBUG] [2368011] [ThreadPool.hpp] [95] - GetInstance success...
this is a task
[2025-02-04 14:41:03 ][INFO] [2368011] [ThreadPool.hpp] [64] - Thread-10 handled a task successfully...
[2025-02-04 14:41:04 ][DEBUG] [2368011] [ThreadPool.hpp] [95] - GetInstance success...
this is a task
[2025-02-04 14:41:04 ][INFO] [2368011] [ThreadPool.hpp] [64] - Thread-5 handled a task successfully...
[2025-02-04 14:41:05 ][DEBUG] [2368011] [ThreadPool.hpp] [95] - GetInstance success...
this is a task
[2025-02-04 14:41:05 ][INFO] [2368011] [ThreadPool.hpp] [64] - Thread-4 handled a task successfully...
[2025-02-04 14:41:06 ][DEBUG] [2368011] [ThreadPool.hpp] [95] - GetInstance success...
this is a task
[2025-02-04 14:41:06 ][INFO] [2368011] [ThreadPool.hpp] [64] - Thread-3 handled a task successfully...
[2025-02-04 14:41:07 ][DEBUG] [2368011] [ThreadPool.hpp] [95] - GetInstance success...
this is a task
[2025-02-04 14:41:07 ][INFO] [2368011] [ThreadPool.hpp] [64] - Thread-2 handled a task successfully...
[2025-02-04 14:41:08 ][DEBUG] [2368011] [ThreadPool.hpp] [95] - GetInstance success...
[2025-02-04 14:41:08 ][INFO] [2368011] [ThreadPool.hpp] [66] - Thread-8 exit success...
[2025-02-04 14:41:08 ][INFO] [2368011] [ThreadPool.hpp] [66] - Thread-7 exit success...
[2025-02-04 14:41:08 ][INFO] [2368011] [ThreadPool.hpp] [66] - Thread-6 exit success...
[2025-02-04 14:41:08 ][INFO] [2368011] [ThreadPool.hpp] [66] - Thread-9 exit success...
[2025-02-04 14:41:08 ][INFO] [2368011] [ThreadPool.hpp] [66] - Thread-10 exit success...
[2025-02-04 14:41:08 ][INFO] [2368011] [ThreadPool.hpp] [66] - Thread-5 exit success...
[2025-02-04 14:41:08 ][INFO] [2368011] [ThreadPool.hpp] [66] - Thread-4 exit success...
[2025-02-04 14:41:08 ][INFO] [2368011] [ThreadPool.hpp] [66] - Thread-3 exit success...
[2025-02-04 14:41:08 ][INFO] [2368011] [ThreadPool.hpp] [66] - Thread-2 exit success...
[2025-02-04 14:41:08 ][INFO] [2368011] [ThreadPool.hpp] [66] - Thread-1 exit success...
[2025-02-04 14:41:13 ][DEBUG] [2368011] [ThreadPool.hpp] [95] - GetInstance success...
[2025-02-04 14:41:13 ][INFO] [2368011] [ThreadPool.hpp] [116] - Thread-1Wait Success...
[2025-02-04 14:41:13 ][INFO] [2368011] [ThreadPool.hpp] [116] - Thread-2Wait Success...
[2025-02-04 14:41:13 ][INFO] [2368011] [ThreadPool.hpp] [116] - Thread-3Wait Success...
[2025-02-04 14:41:13 ][INFO] [2368011] [ThreadPool.hpp] [116] - Thread-4Wait Success...
[2025-02-04 14:41:13 ][INFO] [2368011] [ThreadPool.hpp] [116] - Thread-5Wait Success...
[2025-02-04 14:41:13 ][INFO] [2368011] [ThreadPool.hpp] [116] - Thread-6Wait Success...
[2025-02-04 14:41:13 ][INFO] [2368011] [ThreadPool.hpp] [116] - Thread-7Wait Success...
[2025-02-04 14:41:13 ][INFO] [2368011] [ThreadPool.hpp] [116] - Thread-8Wait Success...
[2025-02-04 14:41:13 ][INFO] [2368011] [ThreadPool.hpp] [116] - Thread-9Wait Success...
[2025-02-04 14:41:13 ][INFO] [2368011] [ThreadPool.hpp] [116] - Thread-10Wait Success...

http://www.ppmy.cn/server/165289.html

相关文章

基于多智能体强化学习的医疗AI中RAG系统程序架构优化研究

一、引言 1.1 研究背景与意义 在数智化医疗飞速发展的当下,医疗人工智能(AI)已成为提升医疗服务质量、优化医疗流程以及推动医学研究进步的关键力量。医疗 AI 借助机器学习、深度学习等先进技术,能够处理和分析海量的医疗数据,从而辅助医生进行疾病诊断、制定治疗方案以…

为AI聊天工具添加一个知识系统 之76 详细设计之17 正则表达式 之4 正则表达式模板

本文要点 要点 1、三“化” 使用三种不同的定义方法&#xff1a; 规定定义法 -线性回归/内涵定义法--一阶迭代/外延定义法--单调递归 整体形成 一个双人零和 的局面 <Class()外延式, Type()内涵式> Method()规定式。给出 问题“law 是什么”的三种答案&#xff1a; …

[paddle] 矩阵相关的指标

行列式 det 行列式定义参考 d e t ( A ) ∑ i 1 , i 2 , ⋯ , i n ( − 1 ) σ ( i 1 , ⋯ , i n ) a 1 , i 1 a 2 , i 2 , ⋯ , a n , i n det(A) \sum_{i_1,i_2,\cdots,i_n } (-1)^{\sigma(i_1,\cdots,i_n)} a_{1,i_1}a_{2,i_2},\cdots, a_{n,i_n} det(A)i1​,i2​,⋯,in​…

2.7学习记录

re [WUSTCTF2020]Cr0ssfun 得到附件先查壳无壳elf64位文件&#xff0c;放进ida查看主调函数往下追踪&#xff0c;发现7部分相似的结构&#xff0c;给的数字看上去像是ASCII码&#xff0c;对照码表把7部分串联起来得到&#xff1a;wctf2020{cpp_nd_r3verse_re_fun} pwn rip …

Vue.js组件开发-实现字母向上浮动

使用Vue实现字母向上浮动的效果 实现步骤 创建Vue项目&#xff1a;使用Vue CLI来创建一个新的Vue项目。定义组件结构&#xff1a;在组件的模板中&#xff0c;定义包含字母的元素。添加样式&#xff1a;使用CSS动画来实现字母向上浮动的效果。绑定动画类&#xff1a;在Vue组件…

无公网IP 外网访问青龙面板

青龙面板是一款基于 Docker 的自动化管理平台&#xff0c;用户可以通过简便的 Web 界面&#xff0c;轻松的添加、管理和监控各种自动化任务。而且这款面板还支持多用户、多任务、任务依赖和日志监控&#xff0c;个人和团队都比较适合使用。 本文将详细的介绍如何用 Docker 在本…

STM32 TIM编码器接口测速

编码器接口简介&#xff1a; Encoder Interface 编码器接口 编码器接口可接收增量&#xff08;正交&#xff09;编码器的信号&#xff0c;根据编码器旋转产生的正交信号脉冲&#xff0c;自动控制CNT自增或自减&#xff0c;从而指示编码器的位置、旋转方向和旋转速度 每个高级定…

DeepSeek 遭 DDoS 攻击背后:DDoS 攻击的 “千层套路” 与安全防御 “金钟罩”

当算力博弈升级为网络战争&#xff1a;拆解DDoS攻击背后的技术攻防战——从DeepSeek遇袭看全球网络安全新趋势 在数字化浪潮席卷全球的当下&#xff0c;网络已然成为人类社会运转的关键基础设施&#xff0c;深刻融入经济、生活、政务等各个领域。从金融交易的实时清算&#xf…