有没有办法找出线程是否被阻止?

时间:2013-07-03 09:36:35

标签: c++ multithreading c++11 threadpool blocking

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

我更喜欢使用C ++ 11标准库或提升以实现可移植性。但如果有必要,我也会使用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个线程调用它。此时所有线程都应该继续运行。线程池的一个要求是它不应该死锁,因为池中的线程数太少。

2 个答案:

答案 0 :(得分:3)

在线程池中添加一个工具,让线程说“我被阻止”,然后“我不再被阻止”。在每次重要的阻止行动之前(见下文我的意思)发出信号“我被阻止”,然后“我不再被阻止”。

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

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

和其他类似事件。

答案 1 :(得分:2)

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

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

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