【问题标题】:ThreadPool - How to delete Worker (this) once it's member thread is finishedThreadPool - 如何在成员线程完成后删除 Worker (this)
【发布时间】:2017-10-31 08:29:23
【问题描述】:

目标是实现在单独的线程中执行任务的 Worker。问题在于正确设计 Worker 关闭路径。所以:

class Worker
{
    /* ... */
    /**
     * @brief Thread pool worker constructor
     *
     * Runs the worker's taskRunner() in the stand alone thread.
    */
    Worker( ThreadPool * threadPool )
    {
        /* Run the task runner in new thread */
        this->mThread = std::thread( std::bind( & Worker::taskRunner, this, threadPool ) );
    }
    /* ... */
};

worker 在独立线程中运行它的成员方法Worker::taskRunner。 taskRunner 看起来像这样(删除了不必要的东西):

void taskRunner( ThreadPool * threadPool )
{
    /* Infinite loop */
    while( this->getState() != State::TERMINATED )
    {
        /* ... */
    }

    /* At this point, the thread is going to be finished */
}

一旦 taskRunner 的无限循环退出,我想删除 Worker 本身,该实例保存在 std::list 集合中的 ThreadPool 类中:

std::list<std::shared_ptr<Worker>> mWorkers;

我想使用void std::list::remove( const T&amp; value ); 方法。

问题在于这个remove()是在哪个作用域调用的。

  1. 如果我在 taskRunner() 方法的末尾调用它,它将 在Worker的线程范围内执行,对吧?但是是不是 从其成员中删除父对象的正确方法 线?
  2. 我也想过用boost::signals2::signal 通知工作对象本身它的线程已完成,因此 工人可以要求线程池删除自己...?不是 矫枉过正?在主要之间发出信号会是一个有意义的解决方案吗 和工作线程?

一般来说,我想避免在主线程(Worker 正在运行的地方)中出现任何阻塞模式...... 非常感谢任何人知道如何解决这个问题......

【问题讨论】:

  • 通常您会将任务传递给线程池类,该类管理任务队列,将任务分配给不同的工作人员,并在一切完成后进行清理。工人被生成一次并等待新任务的到来。线程池的重点是不必为每个新任务生成一个新线程,这可能非常昂贵。如果您为每个任务生成一个新线程,为什么还要有一个 Worker 类?
  • @cantordust 你是对的。线程池应管理从队列中获取任务的有限数量的工作人员。这就是线程池的原理。但是,如果任务在某种程度上依赖于等待——一项任务可能会等待另一项也被阻止或什至没有安排的任务。在这种情况下,解决方案是临时添加另一个执行此工作的工人。一旦情况发生变化,工人的数量就会再次受到限制。长话短说,线程池应保持定义数量的活动工作线程,而不是保持恒定数量的可能等待线程。
  • 我明白了。只是一个建议:如果某些任务需要等待其他任务完成,也许您可​​以使用优先级队列(可能是std::priority_queue&lt;std::shared_ptr&lt;Worker&gt;&gt;?)。在Worker 类中定义优先级,并为队列提供一个自定义比较器,以首先调度具有最高优先级的工作人员。然后,当您一次弹出一个任务时,您将按优先级顺序处理任务,您可以在完成后立即丢弃工作人员。
  • @cantordust 哦,好主意!但是std::priority_queue 应该用于任务队列,不是吗?工人只是被保存在某个容器中(std::list),它允许从列表中的任何位置插入和删除恒定时间元素(这是我的选择标准)
  • std::list 具有恒定的时间插入和删除元素,但前提是您已经有一个指向正确元素的迭代器。否则,您将不得不将列表遍历到正确的位置,这平均是线性时间。我建议std::unordered_map,因为它具有恒定时间插入、擦除和查找功能。关于priority_queue,我在考虑std::priority_queue&lt;std::shared_ptr&lt;Worker&gt;&gt;,甚至只是std::priority_queue&lt;Worker&gt;Worker 可以有一个数据成员 int priority,一个 std::thread 持有任务,operator () 执行任务。

标签: c++ multithreading c++11 c++14 worker


【解决方案1】:

您可以使用一些惰性删除例程,使用单个管家线程以特定间隔检查列表,并通过调用 Worker::getState() 检查其状态,从列表中删除已完成的 Worker 对象。

【讨论】:

  • 您是否需要在 threadPool 本身中实现另一个检查线程,该线程将不断轮询工作人员的状态并删除已终止的工作人员?
  • 是的,这种实现有点像JAVA垃圾回收机制。
  • ...也许使用std::condition_variable 触发它以减少负载...对我来说很有意义!非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-13
  • 2013-03-07
  • 2012-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-17
相关资源
最近更新 更多