c++ - 线程构建 block : Deadlocks because all threads used up

标签 c++ multithreading c++11 deadlock tbb

在英特尔线程构建 block 框架中,如何确保所有线程不忙于等待其他线程完成。

例如考虑以下代码,

#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 调度程序会发现没有线程可用,并且只是死锁。也就是说,我看到该打印语句在 4 个超线程机器上正好经过 4 次,在 8 个超线程机器上正好经过 8 次。

我该如何避免这种情况,特别是有没有办法确保两个 task_grouptask_arenaparallel_for 构造使用两个完全不相交的线程集?

最佳答案

std::future 与 TBB 的可选并行范例不兼容。 std::future::get() 实际上应该命名为 let_me_block_in_system_wait_here()。除非你想让 TBB 死锁,否则禁止在 TBB 任务调度程序不知道的 TBB 任务之间实现任何类型的同步。也就是说,使用 TBB 方式表达 TBB 任务之间的依赖关系。

可选的并行性意味着您的代码必须仅使用单个线程正确运行。只有 tbb::task::enqueue() promise 除了主线程之外至少有一个工作线程。

您的代码甚至不应该编译,因为您在 main() 中使用了 g.run() 而没有声明 g。并且禁止在调用wait()之前销毁task_group,如the reference所述对于析构函数:要求:在销毁 task_group 之前必须调用方法 wait,否则析构函数会抛出异常。

至于共享线程池。是的,TBB 有一个共享线程池。但是您可以使用 task_arena 控制工作的共享方式。没有任务可以离开竞技场,但工作线程可以在运行任务之间的时间内跨竞技场迁移。

关于c++ - 线程构建 block : Deadlocks because all threads used up,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31605578/

相关文章:

multithreading - 如果操作系统管理的同一进程中的两个线程同时访问同一虚拟地址,那么在两个执行单元中会发生什么?

c++ - 无法使用成员函数更改私有(private)变量

C++ 将类成员函数传递给其他类

c++ - 如何安全地重载 std::unique_ptr 的自定义删除器?

c++ - 公共(public)成员功能问题

c++ - 如何实现unsigned abs(int)?

c - 如何编写线程安全的程序?

c++ - 原子类对象方法的用法

c++ - 如何在不移动的情况下交换 map 元素?

c++ - static_cast int 引用 int?