【问题标题】:tbb::parallel_for_each not executing while cancelingtbb::parallel_for_each 在取消时未执行
【发布时间】:2020-05-07 19:45:42
【问题描述】:

我在task_group 的深处运行tbb::parallel_for_eachtask_group 被取消,这似乎导致 tbb::parallel_for_each 在不满足其后置条件的情况下退出。这是最小的测试用例:

tbb::task_group g;
std::vector<int> x { 0, 0, 0, 0 };
std::atomic<std::size_t> counter {0};
g.run([&x, &counter]() {
    std::cout << "in run()\n" << std::flush;
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::cout << "in run(): slept\n" << std::flush;
    assert(tbb::task::self().is_cancelled());

    tbb::parallel_for_each(x, [&counter](int& y) {
        std::cout << "in run(): in parallel_for_each\n" << std::flush;
        ++y;
        ++counter;
    });
    assert(counter == x.size());
});
std::cout << "canceling\n" << std::flush;
g.cancel();
std::cout << "canceled " << g.is_canceling() << " " << tbb::task::self().is_cancelled() << std::endl;
assert(g.is_canceling());
std::cout << "canceled " << g.is_canceling() << " " << tbb::task::self().is_cancelled() << std::endl;
g.wait();
std::cout << "canceled " << g.is_canceling() << " " << tbb::task::self().is_cancelled() << std::endl;

即:它在一个等待 0.1 秒的函数上调用 tbb::task_group 调用 run,然后循环一个向量。它计算循环进行了多少次迭代。然后它cancel()s 任务组。输出是

canceling
in run()
canceled 1 0
canceled 1 0
in run(): slept
Assertion failed: (counter == x.size()), function operator(), file test.cpp

也就是说,内循环永远不会发生。不过,令我惊讶的是,tbb::parallel_for_each 被调用并无一例外地退出,但它的后置条件(执行循环)没有得到满足!

  1. 这是预期的行为吗?文档没有给出任何警告:https://software.intel.com/en-us/node/506160
  2. 如何检查这种行为?如果我想确保它确实完成了它的工作,我是否总是必须在调用 tbb::parallel_for_each 后检查 tbb::task::self().is_cancelled()
  3. 在这种情况下tbb::parallel_for_each不应该抛出异常(或者至少返回bool)?

我可以通过使用像这样的隔离上下文 (https://software.intel.com/en-us/node/506075) 来“解决”这个问题:

    tbb::task_group_context root(tbb::task_group_context::isolated);
    tbb::parallel_for_each(x, [&counter](int& y) {
        std::cout << "in run(): in parallel_for_each\n" << std::flush;
        ++y;
        ++counter;
    }, root);

但目前,我不确定何时可以信任 tbb::parallel_for_each 来完成它的工作。

【问题讨论】:

标签: c++ tbb cancellation


【解决方案1】:

在任务组内,对tbb::parallel_for_each 的调用从属于任务组的上下文。

取消该任务组将取消它,以及所有从属任务组。我找不到文档中“下级任务组”的定义位置,但它似乎是“任务树”中组下的组。

已取消的tbb::parallel_for_each 不保证其所有迭代都已完成。没有违反发布条件。

你取消了任务组,这也取消了下属tbb::parallel_for_each的隐式任务组,所以它不做操作。

您的隔离上下文可防止取消传播到每个任务组的并行中。您可以通过在调用 parallel_for_each 之前取消 root 来复制该代码中的效果。

【讨论】:

  • 谢谢。这是我得出的结论。除了tbb::task::self().is_cancelled() 之外,还有其他条件tbb::parallel_for_each 不会做它被要求做的所有事情吗?如在tbb::parallel_for_each 之后检查tbb::task::self().is_cancelled() 是否足够?鉴于它没有直接记录在 tbb::parallel_for_each 页面中,我真的觉得它应该是一个例外。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多