背景
基于C++11的线程池,如果线程与任务无关,比较好实现,但是!Opengl这种任务需要绘制上下文,就是需要指定线程执行任务。
代码
thread_pool.hpp
#ifndef _THREAD_POOL_H_
#define _THREAD_POOL_H_
#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>
#include <functional>
#include <vector>
#include <queue>
#include <sstream>
class ThreadPool
{
public:
using Task = std::function<bool()>;//KEY 通常的用法是std::function<void()>;那么回调函数没有返回值,无法判断是否执行完成
explicit ThreadPool(int num) : thread_num_(num), is_running_(false)
{}
~ThreadPool()
{
if (is_running_)
stop();
}
void start()
{
is_running_ = true;
// start threads
for (int i = 0; i < thread_num_; i++)
threads_.emplace_back(std::thread(&ThreadPool::work, this));
}
std::vector<uint64_t> GetThreadIDs()
{
std::unique_lock<std::mutex> lk(mtx_);
return thread_ids_;
}
void stop()
{
{
// stop thread pool, should notify all threads to wake
std::unique_lock<std::mutex> lk(mtx_);
is_running_ = false;
cond_.notify_all(); // must do this to avoid thread block
}
// terminate every thread job
for (std::thread& t : threads_)
{
if (t.joinable())
t.join();
}
thread_ids_.clear();
threads_.clear();
}
void appendTask(const Task& task)
{
if (is_running_)
{
std::unique_lock<std::mutex> lk(mtx_);
tasks_.push(task);
//cond_.notify_one(); // wake a thread to to the task
cond_.notify_all();//广播的方式通知所有线程
}
}
private:
void work()
{
std::thread::id id = std::this_thread::get_id();
std::stringstream ss;
ss << std::this_thread::get_id();
uint64_t thread_current = std::stoull(ss.str());
thread_ids_.push_back(thread_current);
// every thread will compete to pick up task from the queue to do the task
while (is_running_)
{
Task task;
std::unique_lock<std::mutex> lk(mtx_);
if (!tasks_.empty())
{
// if tasks not empty,
// must finish the task whether thread pool is running or not
task = tasks_.front();
}
else if (is_running_ && tasks_.empty())
{
cond_.wait(lk);
}
if (task)
{
if (task()) // do the task 回调是否成功完成
{
tasks_.pop(); // remove the task
}
cond_.wait(lk);
}
}
}
public:
// disable copy and assign construct
ThreadPool(const ThreadPool&) = delete;
ThreadPool& operator=(const ThreadPool& other) = delete;
private:
std::atomic_bool is_running_; // thread pool manager status
std::mutex mtx_;
std::condition_variable cond_;
int thread_num_;
std::vector<std::thread> threads_;
std::vector<uint64_t> thread_ids_;
std::queue<Task> tasks_;
};
#endif // !_THREAD_POOL_H_
应用
//启动线程池
thread_pool_ = shared_ptr<ThreadPool>(new ThreadPool(20));;
thread_pool_->start();
...
//添加任务
thread_pool_->appendTask(std::bind(&Worker::ConsumerFunction, this, msg, thread_id));
...
//callback
bool Worker::ConsumerFunction(Message msg, uint64_t thread_id)
{
std::unique_lock<std::mutex> g(mutex_);
std::stringstream ss;
ss << std::this_thread::get_id();
uint64_t thread_current = std::stoull(ss.str());
std::cout << "ConsumerFunction thread_current " << thread_current << std::endl;
std::cout << "ConsumerFunction thread_id " << thread_id << std::endl;
if (thread_current != thread_id)
{
return false;
}
//do real job
std::cout << "do real job \n";
}
后续
任务和线程的匹配关系,需要另外维护