Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 是否将std::packaged_任务添加到现有线程?_C++_Multithreading_C++11_Packaged Task - Fatal编程技术网

C++ 是否将std::packaged_任务添加到现有线程?

C++ 是否将std::packaged_任务添加到现有线程?,c++,multithreading,c++11,packaged-task,C++,Multithreading,C++11,Packaged Task,是否有一种标准方法可以将std::packaged_任务添加到现有线程?在任务运行之前,必须发生大量的开销,所以我想做一次,然后保持线程运行并等待任务执行。我希望能够使用futures,以便有选择地获得任务的结果并捕获异常 我的C++11之前的实现要求我的任务通过Run()方法(有点麻烦,不能使用lambdas)从抽象基类继承,并且有一个std::deque集合,这些集合是我在主线程中添加到的,在工作线程中从中退出的。我必须保护该集合不被同时访问,并向工作线程提供一个信号,告诉它有什么事情要做,

是否有一种标准方法可以将
std::packaged_任务添加到现有线程?在任务运行之前,必须发生大量的开销,所以我想做一次,然后保持线程运行并等待任务执行。我希望能够使用futures,以便有选择地获得任务的结果并捕获异常


我的C++11之前的实现要求我的任务通过
Run()
方法(有点麻烦,不能使用lambdas)从抽象基类继承,并且有一个
std::deque
集合,这些集合是我在主线程中添加到的,在工作线程中从中退出的。我必须保护该集合不被同时访问,并向工作线程提供一个信号,告诉它有什么事情要做,这样它就不会旋转或休眠。Enquenting返回一个“result”对象,其中包含一个等待任务完成的同步对象,以及一个结果值。这一切都很好,但如果有更好的东西,是时候升级了。

这里有一个玩具线程池:

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;
};
模板
结构线程队列{
使用lock=std::unique_lock;
无效推回(T){
{
锁l(m);
数据。推回(std::move(t));
}
cv.通知_one();
}
boost::可选的pop_front(){
锁l(m);
wait(l,[this]{return abort | | |!data.empty();});
if(abort)返回{};
auto r=std::move(data.back());
data.pop_back();
返回std::move(r);
}
无效终止(){
{
锁l(m);
中止=真;
data.clear();
}
cv.通知所有人();
}
~u队列()
{
终止();
}
私人:
std::互斥m;
std::deque数据;
std::条件变量cv;
bool abort=false;
};
结构线程池{
线程池(std::size_t n=1){start_线程(n);}
线程池(线程池&&)=删除;
线程池&运算符=(线程池&&)=删除;
~thread_pool()=default;//或`{terminate();}`如果要放弃某些任务
模板
std::未来队列任务(F任务){
std::打包任务p(std::移动(任务));
自动r=p。获取未来();
任务。推回(std::move(p));
返回r;
}
模板
std::未来运行任务(F任务){
如果(线程数\活动线程数()>=总线程数()){
启动_线程();
}
返回队列_任务(std::move(task));
}
无效终止(){
tasks.terminate();
}
std::size\u t threads\u active()常量{
主动返回;
}
std::size\u t总线程数()常量{
返回线程。size();
}
无效清除_线程(){
终止();
线程。清除();
}
无效起始螺纹(标准::尺寸n=1){
而(n-->0){
把你推回去(
std::async(std::launch::async,
[本]{
while(auto task=tasks.pop_front()){
++活跃的;
试一试{
(*任务)();
}捕获(…){
--活跃的;
投掷;
}
--活跃的;
}
}
)
);
}
}
私人:
向量线程;
线程队列任务;
std::原子活性;
};
抄袭自我的一本书

带有1个线程的
线程池
与您的描述非常匹配

以上只是一个玩具,一个真正的线程池,我想用
move\u only\u函数
替换
std::packaged\u任务
,这就是我使用它的全部目的。(一个
packaged_任务
如果效率不高,可以很有趣地容纳一个
packaged_任务)


你将不得不考虑关闭的原因并制定一个计划。如果您试图在不清除线程的情况下关闭上述代码,则会将其锁定。

使用?@Adam我不需要线程池,只需要一个线程。您需要一个包含1个线程的线程池。;)我是认真的,我一直在用它。开销(由一个线程向量代替一个线程向量)很小。而且,维护线程池的代码要比维护线程池和拥有任务队列的线程容易得多。第二个只是第一个的一个特例。@Yakk AdamNevraumont请将此作为回答,我会接受的。