在英特尔线程构建块框架中,如何确保所有线程都不忙于等待其他线程完成。
考虑以下代码,
#include <tbb/tbb.h>
#include <vector>
#include <cstdlib>
#include <future>
#include <iostream>
std::future<bool> run_something(std::function<bool(bool)> func, bool b) {
auto task = std::make_shared<std::packaged_task<bool()> >(std::bind(func, b));
std::future<bool> res = task->get_future();
tbb::task_group g;
g.run([task]() { (*task)(); });
return res;
};
int main() {
tbb::parallel_for(0, 100, 1, [=](size_t i) {
g.run([] () {
std::cout << "A" << std::endl;
run_something([] (bool b) { return b; }, true).get();
});
});
return EXIT_SUCCESS;
}
这里main
函数产生的任务与TBB库使用的线程池中的线程一样。然后,当在run_something
函数中发生第二次产生更多任务的调用时,TBB调度程序会发现没有线程可用且只是死锁。那就是我看到那个print语句在4个超线程机器上完成了4次,在8个超线程机器上完成了8次。
如何避免这种情况,特别是,是否有办法确保两个task_group
或task_arena
或parallel_for
结构使用两个完全不相交的线程?
答案 0 :(得分:2)
std::future
与TBB的可选并行范例不兼容。 std::future::get()
应该真正命名为let_me_block_in_system_wait_here()
。除非您希望TBB死锁,否则禁止在TBB任务调度程序不知道的TBB任务之间实现任何类型的同步。也就是说,使用TBB表示TBB任务之间的依赖关系。
可选的并行性意味着您的代码必须仅使用一个线程才能正确运行。除了主线程外,只有tbb::task::enqueue()
为您提供至少一个工作者的承诺。
您的代码甚至不应该编译,因为您在g.run()
中使用main()
而未声明g
。如the reference中针对析构函数所述,task_group
之前禁止销毁wait()
:Requires: Method wait must be called before destroying a task_group, otherwise the destructor throws an exception.
至于共享线程池。是的,TBB有一个共享线程池。但您可以使用task_arena
控制工作的共享方式。没有任务可以离开竞技场,但工作线程可以在运行任务之间的时间跨区域迁移。