前言:
一、关键组件实现
1、任务队列
任务队列的主要功能是保存要执行的任务,有下面这些需要解决的问题
问题一:如何保证任务的通用性?
因为任务队列要有通用性,所以规定任务队列中存储的类型为
using Task = std::packaged_task<void()>;
因为要投递任务给线程池,任务的功能和参数都不同,而之前设置的线程池执行的task类型为
void(void)
,返回值为void
,参数为void
的任务。那可用参数绑定的方式将一个函数绑定为void(void)
类型,例如:
int functionint(int param) {
std::cout << "param is " << param << std::endl;
return 0;
}
void bindfunction() {
std::function<int(void)> functionv = std::bind(functionint, 3);
functionv();
}
假设希望任务队列里的任务要调用
functionint
函数参数为3,因为在投递任务时就知道任务要执行的函数和参数,所以可以将执行的函数和参数绑定生成参数为void
的函数。通过bindfunction
将functionint
绑定为一个返回值为int
参数为void
的新函数functionv
,如下:
void pushtasktoque() {
std::function<int(void)> functionv = std::bind(functionint, 3);
using Task = std::packaged_task<void()>;
std::queue<Task> taskque;
taskque.emplace([functionv]() {
functionv();
});
}
上面只是通过具体的函数和参数实现了投递任务的功能,而实际情况是要投递各种类型的任务,以及多种类型和多个参数,该怎么实现
enqueue
函数更通用呢?对于更通用的设计通常采用模板,如下:
在这里插入代码片
实际投递任务的接口实现如下:
template<class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>
{
using return_type = typename std::result_of<F(Args...)>::type;
auto task = std::make_shared< std::packaged_task<return_type()> >(
std::bind(std::forward<F>(f), std::forward<Args>(args)...));
std::future<return_type> res = task->get_future();
{
std::unique_lock<std::mutex> lock(queue_mutex);
// don't allow enqueueing after stopping the pool
if (stop)
throw std::runtime_error("enqueue on stopped ThreadPool");
tasks.emplace([task](){ (*task)(); });
}
condition.notify_one();
return res;
}
问题二:如何获取任务是否完成?