6

我正在用 C++ 编写一个线程池类,它接收要并行执行的任务。如果可能的话,我希望所有内核都处于忙碌状态,但有时某些线程是空闲的,因为它们出于同步目的而被阻塞了一段时间。发生这种情况时,我想启动一个新线程,以便始终有大约与 cpu 内核一样多的线程处于唤醒状态。为此,我需要一种方法来确定某个线程是唤醒还是休眠(阻塞)。我怎样才能找到这个?

出于可移植性目的,我更喜欢使用 C++11 标准库或 boost。但如有必要,我也会使用 WinAPI。我在 Windows 7 上使用 Visual Studio 2012。但实际上,我希望有一种可移植的方式来执行此操作。

最好这个线程池应该能够掌握这样的情况

MyThreadPool pool;
for ( int i = 0; i < 100; ++i )
    pool.addTask( &block_until_this_function_has_been_called_a_hundred_times );
pool.join(); // waits until all tasks have been dispatched.

函数block_until_this_function_has_been_called_a_hundred_times()阻塞直到 100 个线程调用它。此时所有线程都应该继续运行。线程池的一个要求是它不应该因为池中的线程数量太少而死锁。

4

2 回答 2

3

向您的线程池添加一个设施,让一个线程说“我被阻止”然后“我不再被阻止”。在每个重要的阻止操作(请参阅下文了解我的意思)之前发出“我被阻止”的信号,然后是“我不再被阻止”。

什么构成“重大阻止行动”?当然不是简单的互斥锁:互斥锁应该只持有很短的时间,所以阻塞互斥锁不是什么大问题。我的意思是:

  • 等待 I/O 完成
  • 等待另一个池任务完成
  • 等待共享队列上的数据

和其他类似事件。

于 2013-07-03T14:06:03.977 回答
2

使用Boost Asio。它有自己的线程池管理和调度框架。基本思想是使用该方法将任务推送到io_service对象,并从尽可能多的 CPU 内核调用线程。您应该在计算运行时创建一个对象,以避免线程在没有足够的作业时退出。post()run()work

Asio 最重要的一点是永远不要使用任何阻塞调用。对于 I/O 调用,使用 Asio 自己的 I/O 对象的异步调用。对于同步,使用strand对象而不是互斥锁。如果您将函数发布到包装在一个链中的 io 服务,那么它可以确保在任何时候最多运行一个属于某个链的任务。如果发生冲突,任务将保留在 Asio 的事件队列中,而不是阻塞工作线程。

但是,使用异步编程有一个缺点。阅读分散在多个异步调用中的代码比阅读具有清晰控制流的代码要困难得多。在设计程序时,您应该意识到这一点。

于 2013-07-03T12:01:09.543 回答