线程池实现范例
1 初始化线程池
确定线程数量,并做好互斥访问
2 启动所有线程
std::vector<std::thread*> threads_;
unique_lock<mutex> lock(mutex_); for (int i = 0; i < thread_num_; i++) { auto th = new thread(&XThreadPool::Run, this); threads_.push_back(th); }
3 准备好任务处理基类和插入任务
///线程分配的任务类 class XTask { public: // 执行具体的任务 virtual int Run() = 0; };
存储任务的列表
std::list<XTask*> tasks_;
插入任务,通知线程池处理
unique_lock<mutex> lock(mutex_); tasks_.push_back(task); condition_.notify_one();
4 获取任务接口
通过条件变量阻塞等待任务
//////////////////////////////////////////////////////////// ///获取任务 XTaskType XThreadPool::GetTask() { unique_lock<mutex> lock(mutex_); if (tasks_.empty()) { condition_.wait(lock);//阻塞等待通知 } if (is_exit_) return nullptr; if (tasks_.empty()) { return nullptr; } auto task = tasks_.front(); tasks_.pop_front(); return task; }
5 执行任务线程入口函数
void XThreadPool::Run() { while(!IsExit()) { //获取任务 auto task = GetTask(); if (!task) continue; try { task‐>Run(); } catch (...) { cerr << "XThreadPool::Run() exception" << endl; } } }
完整代码如下:
xthread_pool.h
#pragma once #include <thread> #include <mutex> #include <vector> #include <list> #include <functional> #include <atomic> class XTask { public: virtual int Run() = 0; std::function<bool()> is_exit = nullptr; }; class XThreadPool { public: ////////////////////////////////////////////// /// 初始化线程池 /// @para num 线程数量 void Init(int num); ////////////////////////////////////////////// /// 启动所有线程,必须先调用Init void Start(); ////////////////////////////////////////////// /// 线程池退出 void Stop(); void AddTask(XTask* task); XTask* GetTask(); //线程池是否退出 bool is_exit() { return is_exit_; } int task_run_count() { return task_run_count_; } private: //线程池线程的入口函数 void Run() ; int thread_num_ = 0;//线程数量 std::mutex mux_; std::vector<std::thread*> threads_; std::list<XTask*> tasks_; std::condition_variable cv_; bool is_exit_ = false; //线程池退出 //正在运行的任务数量,线程安全 std::atomic<int> task_run_count_ = {0}; };
xthread_pool.cpp
#include "xthread_pool.h" #include <iostream> using namespace std; ////////////////////////////////////////////// /// 初始化线程池 /// @para num 线程数量 void XThreadPool::Init(int num) { unique_lock<mutex> lock(mux_); this->thread_num_ = num; cout << "Thread pool Init " << num << endl; } ////////////////////////////////////////////// /// 启动所有线程,必须先调用Init void XThreadPool::Start() { unique_lock<mutex> lock(mux_); if (thread_num_ <= 0) { cerr << "Please Init XThreadPool" << endl; return; } if (!threads_.empty()) { cerr << "Thread pool has start!" << endl; return; } //启动线程 for (int i = 0; i < thread_num_; i++) { auto th = new thread(&XThreadPool::Run, this); threads_.push_back(th); } } ////////////////////////////////////////////// /// 线程池退出 void XThreadPool::Stop() { is_exit_ = true; cv_.notify_all(); for (auto& th : threads_) { th->join(); } unique_lock<mutex> lock(mux_); threads_.clear(); } //线程池线程的入口函数 void XThreadPool::Run() { cout << "begin XThreadPool Run " << this_thread::get_id() << endl; while (!is_exit()) { auto task = GetTask(); if (!task)continue; ++task_run_count_; try { task->Run(); } catch (...) { } --task_run_count_; } cout << "end XThreadPool Run " << this_thread::get_id() << endl; } void XThreadPool::AddTask(XTask* task) { unique_lock<mutex> lock(mux_); tasks_.push_back(task); task->is_exit = [this] {return is_exit(); }; lock.unlock(); cv_.notify_one(); } XTask* XThreadPool::GetTask() { unique_lock<mutex> lock(mux_); if (tasks_.empty()) { cv_.wait(lock); } if (is_exit()) return nullptr; if (tasks_.empty()) return nullptr; auto task = tasks_.front(); tasks_.pop_front(); return task; }
main.cpp
#include "xthread_pool.h" #include <iostream> using namespace std; class MyTask :public XTask { public: int Run() { cout << "================================================" << endl; cout << this_thread::get_id()<<" Mytask " << name << endl; cout << "================================================" << endl; for (int i = 0; i < 10; i++) { if (is_exit())break; cout << "." << flush; this_thread::sleep_for(500ms); } return 0; } std::string name = ""; }; int main(int argc, char* argv[]) { XThreadPool pool; pool.Init(16); pool.Start(); MyTask task1; task1.name = "test name 001"; pool.AddTask(&task1); MyTask task2; task2.name = "test name 002"; pool.AddTask(&task2); this_thread::sleep_for(100ms); cout << "task run count = " << pool.task_run_count() << endl; this_thread::sleep_for(1s); pool.Stop(); cout << "task run count = " << pool.task_run_count() << endl; getchar(); return 0; }
智能指针版本改进结果
实现如下:
xthread_pool.h
#pragma once #include <thread> #include <mutex> #include <vector> #include <list> #include <functional> #include <atomic> #include <future> class XTask { public: virtual int Run() = 0; std::function<bool()> is_exit = nullptr; auto GetReturn() { //阻塞等待 set_value return p_.get_future().get(); } void SetValue(int v) { p_.set_value(v); } private: //用来接收返回值 std::promise<int> p_; }; class XThreadPool { public: ////////////////////////////////////////////// /// 初始化线程池 /// @para num 线程数量 void Init(int num); ////////////////////////////////////////////// /// 启动所有线程,必须先调用Init void Start(); ////////////////////////////////////////////// /// 线程池退出 void Stop(); //void AddTask(XTask* task); void AddTask(std::shared_ptr<XTask> task); std::shared_ptr<XTask> GetTask(); //线程池是否退出 bool is_exit() { return is_exit_; } int task_run_count() { return task_run_count_; } ~XThreadPool() { Stop(); } private: //线程池线程的入口函数 void Run() ; int thread_num_ = 0;//线程数量 std::mutex mux_; //std::vector<std::thread*> threads_; //线程列表 指针指针版本 std::vector< std::shared_ptr<std::thread> > threads_; //std::list<XTask*> tasks_; std::list<std::shared_ptr<XTask> > tasks_; std::condition_variable cv_; bool is_exit_ = false; //线程池退出 //正在运行的任务数量,线程安全 std::atomic<int> task_run_count_ = {0}; };
xthread_pool.cpp
#include "xthread_pool.h" #include <iostream> using namespace std; ////////////////////////////////////////////// /// 初始化线程池 /// @para num 线程数量 void XThreadPool::Init(int num) { unique_lock<mutex> lock(mux_); this->thread_num_ = num; cout << "Thread pool Init " << num << endl; } ////////////////////////////////////////////// /// 启动所有线程,必须先调用Init void XThreadPool::Start() { unique_lock<mutex> lock(mux_); if (thread_num_ <= 0) { cerr << "Please Init XThreadPool" << endl; return; } if (!threads_.empty()) { cerr << "Thread pool has start!" << endl; return; } //启动线程 for (int i = 0; i < thread_num_; i++) { //auto th = new thread(&XThreadPool::Run, this); auto th = make_shared<thread>(&XThreadPool::Run, this); threads_.push_back(th); } } ////////////////////////////////////////////// /// 线程池退出 void XThreadPool::Stop() { is_exit_ = true; cv_.notify_all(); for (auto& th : threads_) { th->join(); } unique_lock<mutex> lock(mux_); threads_.clear(); } //线程池线程的入口函数 void XThreadPool::Run() { cout << "begin XThreadPool Run " << this_thread::get_id() << endl; while (!is_exit()) { auto task = GetTask(); if (!task)continue; ++task_run_count_; try { auto re = task->Run(); task->SetValue(re); } catch (...) { } --task_run_count_; } cout << "end XThreadPool Run " << this_thread::get_id() << endl; } void XThreadPool::AddTask(std::shared_ptr<XTask> task) { unique_lock<mutex> lock(mux_); tasks_.push_back(task); task->is_exit = [this] {return is_exit(); }; lock.unlock(); cv_.notify_one(); } std::shared_ptr<XTask> XThreadPool::GetTask() { unique_lock<mutex> lock(mux_); if (tasks_.empty()) { cv_.wait(lock); } if (is_exit()) return nullptr; if (tasks_.empty()) return nullptr; auto task = tasks_.front(); tasks_.pop_front(); return task; }
xvideo_task.h:
#pragma once
#include "xthread_pool.h"
class XVideoTask :public XTask
{
public:
std::string in_path;
std::string out_path;
int width = 0;
int height = 0;
private:
int Run();
};
xvideo_task.cpp
#include "xvideo_task.h" #include <sstream> using namespace std; int XVideoTask::Run() { //ffmpeg -y -i test.mp4 -s 400x300 400.mp4 >log.txt 2>&1 stringstream ss; ss << "ffmpeg.exe -y -i " << in_path<<" "; if (width > 0 && height > 0) ss << " -s " << width << "x" << height<<" "; ss << out_path; ss << " >" << this_thread::get_id() << ".txt 2>&1"; return system(ss.str().c_str()); }
main.cpp
#include "xthread_pool.h" #include "xvideo_task.h" #include <iostream> using namespace std; /// 命令行视频转码工具 /// ffmpeg工具 /// 用户输入 视频源 输出视频尺寸 /// 在线程池中执行转码任务 /// 转码任务调用ffmpeg /// ffmpeg -y -i test.mp4 -s 400x300 400.mp4 >log.txt 2>&1 int main(int argc, char* argv[]) { XThreadPool pool; pool.Init(16); pool.Start(); this_thread::sleep_for(200ms); for (;;) { this_thread::sleep_for(200ms); cout << "\n====================================================================\n"; auto task = make_shared<XVideoTask>(); cout << "请输入命令(v e l):"; string cmd; cin >> cmd; if (cmd == "e") break; else if (cmd == "l") { cout << "task run count = " << pool.task_run_count() << endl; continue; } cout << "视频源:"; cin >> task->in_path; cout << "目标:"; cin >> task->out_path; cout << "输出宽:"; cin >> task->width; cout << "输出高:"; cin >> task->height; pool.AddTask(task); } pool.Stop(); /* auto vtask1 = make_shared<XVideoTask>(); vtask1->in_path = "test.mp4"; vtask1->out_path = "640.mp4"; vtask1->width = 640; vtask1->height = 480; pool.AddTask(vtask1); vtask1->GetReturn(); */ return 0; }
线程池实现范例二:
MessageQueue.hpp
#ifndef _AD_META_MESSAGE_QUEUE_HPP_ #define _AD_META_MESSAGE_QUEUE_HPP_ #include <condition_variable> #include <mutex> #include <queue> template < typename T_ > class MMessageQueue { public: MMessageQueue() : queue_(), mutex_(), condition_() {} virtual ~MMessageQueue() {} inline virtual void push(T_&& t) { { std::unique_lock< std::mutex > lock(this->mutex_); this->queue_.push(t); } // notify_one out of critical area to optimize perf this->condition_.notify_one(); } inline virtual void push(T_& t) { { std::unique_lock< std::mutex > lock(this->mutex_); this->queue_.push(t); } this->condition_.notify_one(); } inline void clear() { std::unique_lock< std::mutex > lock(this->mutex_); std::queue< T_ > q; this->queue_.swap(q); } inline size_t size() { std::unique_lock< std::mutex > lock(this->mutex_); return this->queue_.size(); } virtual T_ pop() { std::unique_lock< std::mutex > lock(this->mutex_); while (this->queue_.size() <= 0U) { this->condition_.wait(lock); } auto ret = std::move(this->queue_.front()); this->queue_.pop(); return ret; } protected: std::queue< T_ > queue_; std::mutex mutex_; std::condition_variable condition_; }; template < typename T_ > class MBoundedUnblockedQueue final : public MMessageQueue< T_ > { public: MBoundedUnblockedQueue(uint32_t size) : size_(size) {} inline virtual void push(T_&& t) override { { std::unique_lock< std::mutex > lock(this->mutex_); if (this->queue_.size() >= this->size_) { this->queue_.pop(); } this->queue_.push(t); } this->condition_.notify_one(); } inline virtual void push(T_& t) override { { std::unique_lock< std::mutex > lock(this->mutex_); if (this->queue_.size() >= this->size_) { this->queue_.pop(); } this->queue_.push(t); } this->condition_.notify_one(); } size_t capacity() { return size_; } private: uint32_t size_; }; template < typename T_ > class MBoundedBlockedQueue final : public MMessageQueue< T_ > { public: MBoundedBlockedQueue(uint32_t size) : size_(size) {} inline virtual void push(T_&& t) override { { std::unique_lock< std::mutex > lock(this->mutex_); while (this->queue_.size() >= this->size_) { this->condition_.wait(lock); } this->queue_.push(t); } this->condition_.notify_one(); } inline virtual void push(T_& t) override { { std::unique_lock< std::mutex > lock(this->mutex_); while (this->queue_.size() >= this->size_) { this->condition_.wait(lock); } this->queue_.push(t); } this->condition_.notify_one(); } virtual T_ pop() override { std::unique_lock< std::mutex > lock(this->mutex_); while (this->queue_.size() <= 0U) { this->condition_.wait(lock); } auto ret = std::move(this->queue_.front()); this->queue_.pop(); lock.unlock(); this->condition_.notify_one(); return ret; } private: uint32_t size_; }; #endif // _AD_META_MESSAGE_QUEUE_HPP_
MThreadPool.hpp
#ifndef _AUTOCOMMON_AUTOSDK_THREAD_POOL_HPP_ #define _AUTOCOMMON_AUTOSDK_THREAD_POOL_HPP_ #include <functional> #include <future> #include <thread> #include "AutoSdkType.hpp" #include "tools/MessageQueue.hpp" namespace AutoSDK { using MThreadPoolTaskProto = void(); using MThreadPoolTaskClosure = std::function<MThreadPoolTaskProto>; class MThreadPool final { public: void Init(uint32_t const thread_num); void Exit(); template <typename Callable, typename... Args> inline std::future<typename std::result_of<Callable(Args...)>::type> Run(Callable&& c, Args&&... args) { using ret_type = typename std::result_of<Callable(Args...)>::type; std::shared_ptr<std::packaged_task<ret_type()> > task{ std::make_shared<std::packaged_task<ret_type()> >( std::bind(std::forward<Callable>(c), std::forward<Args>(args)...))}; this->queue_.push([task]() { (*task)(); }); return task->get_future(); } private: void PopRun(); private: ::MMessageQueue<MThreadPoolTaskClosure> queue_; std::vector<std::thread> runner_; uint32_t state; }; } // namespace AutoSDK #endif // _AUTOCOMMON_AUTOSDK_THREAD_POOL_HPP_
MthreadPool.cpp
#include "MThreadPool.hpp" namespace AutoSDK { void MThreadPool::Init(uint32_t const thread_num) { this->Exit(); this->runner_.clear(); this->state = 0U; this->runner_.resize(static_cast<size_t>(thread_num)); for (auto& r : this->runner_) { r = std::thread(&MThreadPool::PopRun, this); } } void MThreadPool::Exit() { this->state = 1U; for (uint32_t i{0U}; i < this->runner_.size(); i++) { this->Run([]() {}); } for (auto& r : this->runner_) { if (r.joinable()) { r.join(); } } } void MThreadPool::PopRun() { while (0U == this->state) { this->queue_.pop()(); } } } // namespace AutoSDK

浙公网安备 33010602011771号