【问题标题】:Can objects in an OpenMP thread be modified from outside?可以从外部修改 OpenMP 线程中的对象吗?
【发布时间】:2019-09-11 13:52:59
【问题描述】:

我使用 OpenMP 来并行化调用,如下所示:

#pragma omp parallel for
  for(std::size_t iter = 0; iter < visitors.size(); ++iter)
    {
      VisitorSPtr visitor_sp = visitors.at(iter);

      dataSetPtr->accept(*(visitor_sp.get());
    }
  // End of
  // #pragma omp parallel for

感谢#pragma omp parallel for 指令,每个访问者都在不同的线程中使用。美好的。

循环中调用的dataSetPtr-&gt;accept() 函数检查访问者是否已被用户取消,如下所示:

    if(visitor.shouldStop())
        break;

如果该调用返回 true,则不执行访问。当用户单击一个按钮并发出一个信号,该信号被传递给访问者,该访问者设置一个成员布尔变量以声明已请求取消时,该取消被捕获。但是信号没有到达访问者,if(visitor.shouldStop()) 没有用,也就是说,即使取消信号被正确发出,也永远不会评估为真。

连接是这样执行的(this 是建立连接的 MassDataIntegrator 对象实例,它接收取消信号并将其中继到访问者实例):

      connect(this,
            &MassDataIntegrator::cancelOperationSignal,
            visitor_sp.get(),
            &Visitor::cancelOperation,
            Qt::QueuedConnection);

我的问题:如何从另一个线程中运行的代码修改 #pragma omp parallel for 循环中的对象?我认为通过使用指针这将是微不足道的。显然,我在这里遗漏了一些概念。有人可以帮我解决这个误解吗?感谢您的关注。

已解决

上面的连接调用由于某种原因不起作用(我将调查)。所以我尝试使用一个 lambda,从表面上看,它像这样直接访问 Visitor 实例(我注释掉了替换的代码以显示差异):

  connect(this,
        &MassDataIntegrator::cancelOperationSignal,
        [visitor_sp](){visitor_sp->cancelOperation();});
          //visitor_sp.get(),
          //&TicChromTreeNodeCombinerVisitor::cancelOperation,
          //Qt::QueuedConnection);

我们可以认为这个问题已经解决了。我该怎么做?

【问题讨论】:

  • 请注意,在目前的表格中,我只能对您的问题给出一般性的回答。如果您的问题仍然存在并且您需要一个具体的答案,请创建一个minimal reproducible example - 最好不要 QT。
  • 谢谢祖蓝的回答。我编辑了这个问题,因为经过一番挖掘后我发现其中存在编程错误。但是,我仍然不知道是否可以从该部分之外修改对象的状态(用于并行部分)。
  • 好的,我现在已经解决了这个问题。我显然对作为对希望取消计算的用户的响应而发出的 Qt 信号存在问题:它没有到达 Visitor 实例。我已将解决方案添加到初始帖子中。
  • 即使它看起来可以正常工作,如果您希望它正确且可移植,请记住我的回答。
  • 是的,祖蓝,你是对的。我需要考虑这一点,尽管在当前的实现中,取消只能来自一个来源,并且会分别影响每个访问者。感谢您的帮助。

标签: c++ openmp


【解决方案1】:

如果您从 OpenMP 中的多个线程访问数据位置,并且至少其中一次访问是写访问,则必须使用 atomic 指令保护对该位置的所有读写访问(或其他避免竞争条件和确保内存一致性的方法)。

简单地说,shouldStop 应该按照以下方式实现:

bool r;
#pragma omp atomic read
r = this->cancelFlag_;
return r;

cancelOperation 喜欢:

#pragma omp atomic write
this->cancelFlag_ = true;

这既确保了在写入bool 需要两个操作的不太可能的情况下不存在竞争条件,并且意味着适当的内存刷新以确保写入的结果在其他线程中可见。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-05
    • 2022-01-17
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 2022-01-15
    相关资源
    最近更新 更多