线程池实现范例
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; }