提升线程池

时间:2012-10-14 09:33:29

标签: c++ multithreading boost threadpool boost-asio

我的应用程序需要一个线程池,我希望尽可能依赖标准(C ++ 11或boost)。我意识到有一个非官方的(!)提升线程池类,它基本上解决了我需要的东西,但是我宁愿避免它,因为它不在boost库本身 - 为什么它仍然不在核心库之后多年?

在本页和其他地方的一些帖子中,人们建议使用boost :: asio来实现类似行为的线程池。乍一看,这看起来像我想要做的,但是我发现我看到的所有实现都无法加入当前活动的任务,这使得它对我的应用程序毫无用处。为了执行连接,它们向所有线程发送停止信号,然后加入它们。但是,这完全消除了我的用例中线程池的优势,因为这使得新任务需要创建新线程。

我想做的是:

ThreadPool pool(4);
for (...)
{
    for (int i=0;i<something;i++)
        pool.pushTask(...);
    pool.join();
    // do something with the results
}

有人可以提出解决方案(除了在sourceforge上使用现有的非官方线程池)吗? C ++ 11或核心提升中有什么可以帮助我吗?

4 个答案:

答案 0 :(得分:3)

  

乍一看,这看起来就像我想做的那样,但是我发现我看到的所有实现都无法加入当前活动的任务,这使得它对我的应用程序毫无用处。为了执行连接,它们向所有线程发送停止信号,然后加入它们。但是,这完全消除了我的用例中线程池的优势,因为这使得新任务需要创建新线程。

我想你可能误解了asio的例子:

IIRC(已经有一段时间了)在线程池中运行的每个线程都调用了io_service::run,这意味着每个线程都有一个事件循环和一个调度程序。然后让asio完成任务,使用io_service :: post方法将任务发布到io_service,并且asio的调度机制负责其余的工作。只要您不调用io_service::stop,线程池将继续使用您开始运行时的线程数运行(假设每个线程都有工作要做,或者已经分配了io_service::work个对象)。

所以你需要为新任务创建新线程,这将违背线程池的概念。

答案 1 :(得分:1)

让每个任务类派生自具有“OnCompletion(task)”方法/事件的Task。然后,线程池线程可以在调用任务的主run()方法之后调用它。

等待单个任务完成很容易。 OnCompletion()可以执行任何信号发送线程所需的信号,发出condvar信号,将任务排队到生产者 - 消费者队列,调用SendMessage / PostMessage API,Invoke / BeginInvoke等等。

如果一个oringinating线程需要等待几个任务完成,你可以扩展上面的内容并向池发出一个“Wait task”。等待任务有自己的OnCompletion来传达其他任务的完成,并具有线程安全的“任务计数器”(原子操作或锁定),设置为要发出的“主要”任务的数量。等待任务首先发送到池,并且运行它的线程在等待任务中的私有'allDone'condvar上等待。然后,将'main'任务发送到池中,并将其OnCompletion设置为调用等待任务的方法,该方法将任务计数器递减为零。当任务计数器达到零时,实现此功能的线程将发出allDone condvar信号。等待任务OnCompletion然后运行,因此表示完成所有主要任务。

这种机制不需要连续创建/终止/加入/删除线程池线程,不需要如何发信号通知原始任务,您可以根据需要发出任意数量的此类任务组。但是,您应该注意,每个等待任务都会阻塞一个线程池线程,因此请确保在池中创建一些额外的线程(通常不会出现任何问题)。

答案 2 :(得分:1)

这似乎是boost::futures的工作。文档中的示例似乎准确地证明了您要做的事情。

答案 3 :(得分:0)

加入一个线程意味着停止它直到它停止,如果它停止并且你想为它分配一个新任务,你必须创建一个新线程。因此,在您的情况下,您应该等待一个条件(例如boost::condition_variable)来指示任务结束。因此,使用此技术可以非常轻松地使用boost::asioboost::condition_variable来实现它。每个线程调用boost::asio::io_service::run和任务将在不同的线程上进行调度和执行,最后,每个任务将设置boost::condition_variable或事件减少std::atomic以指示作业结束!这真的很容易,不是吗?