有没有添加的标准方法std::packaged_task
现有的线程? 有开销运行任务之前必须发生的平凡的数额,所以我想这样做一次,然后继续线程运行并等待任务来执行。 我希望能够利用期货这样我就可以根据需要获取任务和捕捉异常的结果。
我的预C ++ 11的实现需要我的任务,从一个抽象基类继承了Run()
方法(有点痛的,不能用lambda表达式),以及具有std::deque
那些收藏我添加到主线程,并从工作线程出列。 我要保护这个集合从同时访问和工作线程提供一个信号,表明有什么东西要做到这一点不旋转或睡觉。 一些入队返回一个“结果”对象与同步对象等待任务来完成,而结果值。 这一切运作良好,但现在是时候进行升级,如果有更好的东西。
这里是一个玩具线程池:
template<class T>
struct threaded_queue {
using lock = std::unique_lock<std::mutex>;
void push_back( T t ) {
{
lock l(m);
data.push_back(std::move(t));
}
cv.notify_one();
}
boost::optional<T> pop_front() {
lock l(m);
cv.wait(l, [this]{ return abort || !data.empty(); } );
if (abort) return {};
auto r = std::move(data.back());
data.pop_back();
return std::move(r);
}
void terminate() {
{
lock l(m);
abort = true;
data.clear();
}
cv.notify_all();
}
~threaded_queue()
{
terminate();
}
private:
std::mutex m;
std::deque<T> data;
std::condition_variable cv;
bool abort = false;
};
struct thread_pool {
thread_pool( std::size_t n = 1 ) { start_thread(n); }
thread_pool( thread_pool&& ) = delete;
thread_pool& operator=( thread_pool&& ) = delete;
~thread_pool() = default; // or `{ terminate(); }` if you want to abandon some tasks
template<class F, class R=std::result_of_t<F&()>>
std::future<R> queue_task( F task ) {
std::packaged_task<R()> p(std::move(task));
auto r = p.get_future();
tasks.push_back( std::move(p) );
return r;
}
template<class F, class R=std::result_of_t<F&()>>
std::future<R> run_task( F task ) {
if (threads_active() >= total_threads()) {
start_thread();
}
return queue_task( std::move(task) );
}
void terminate() {
tasks.terminate();
}
std::size_t threads_active() const {
return active;
}
std::size_t total_threads() const {
return threads.size();
}
void clear_threads() {
terminate();
threads.clear();
}
void start_thread( std::size_t n = 1 ) {
while(n-->0) {
threads.push_back(
std::async( std::launch::async,
[this]{
while(auto task = tasks.pop_front()) {
++active;
try{
(*task)();
} catch(...) {
--active;
throw;
}
--active;
}
}
)
);
}
}
private:
std::vector<std::future<void>> threads;
threaded_queue<std::packaged_task<void()>> tasks;
std::atomic<std::size_t> active;
};
从复制另一个答案矿井。
一个thread_pool
1线你的描述相符漂亮多了。
以上只是一个玩具,一个真正的线程池我更换std::packaged_task<void()>
与move_only_function<void()>
,这是我用它。 (A packaged_task<void()>
可以容纳packaged_task<R()>
有趣的是,如果inefficiencly)。
你将不得不推理关机并制定一个计划。 如果你试图关闭它在清除线程上面的代码锁定。