首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >理解tbb::parallel_reduce的并发性

理解tbb::parallel_reduce的并发性
EN

Stack Overflow用户
提问于 2017-03-23 10:33:36
回答 2查看 406关注 0票数 0

我使用命令式的tbb::parallel_reduce(range,body)形式作为记录在这里。医生说:

parallel_reduce使用拆分构造函数为每个线程创建一个或多个主体副本。当主体的操作符()或方法join同时运行时,它可以复制一个主体。您有责任确保这种并发的安全。

因此,我理解Body::Body( Body&, split )可以像Body::operator()Body::join( Body& rhs )那样运行。

我的问题是

1) Body::operator()Body::join( Body& rhs )能否同时运行?

2) Body::join( Body& rhs )能安全地修改rhs吗?

W.r.t.1)我认为,join只能在operator()完成后调用。此外,看看Intel文档中的示例,很明显,它们可以修改相同的数据,而不会出现数据争用问题:

代码语言:javascript
复制
struct Sum {
    float value;
    ...
    void operator()( const blocked_range<float*>& r ) {
        value = ...;
    }
    void join( Sum& rhs ) {value += rhs.value;}
};               
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-03-25 23:28:07

Body对象由tbb::parallel_reduce使用的生存期为:

  1. 它由拆分构造函数作为另一个Body对象的“右侧”创建,然后更新为只处理“左侧”对象。
  2. 它的operator()应用于一个或多个后续范围。
  3. 它可以用作拆分新主体的构造函数的参数(是的,不止一次),并按照上面的#1进行更新。
  4. 它的方法join()是为#3中从它分割的每个对象调用的。
  5. 它以rhs的形式加入到它被拆分的body对象中。
  6. 它在加入后就被摧毁了。

在上面的操作中,#3可以并发运行到#2和#4;其余操作都是连续的,即使不一定由单个线程调用。换句话说,当一个主体为某个子区间积累部分约简或加入另一个体的结果时,它可以通过拆分新体的构造函数来更新。这是可能需要保护的地方,但通常情况下,这些呼叫会访问身体的不同部分。

所以,你的问题的答案是:

1) Body::operator()Body::join( Body& rhs )能否同时运行?

不是的。join()只会被调用到operator(),包括thisrhs

2) Body::join( Body& rhs )能安全地修改rhs吗?

是的,它可以。但是,除了可能在联接期间移动其内容并相应地更新状态外,修改rhs没有什么意义,因为它将在join()调用之后立即销毁。

票数 2
EN

Stack Overflow用户

发布于 2017-03-23 22:55:06

对于在并发调用方法中涉及哪些实例,文档还不够清楚。但它暗示:

在典型的使用中,安全不需要额外的努力。

同一实例没有并发性。因此,在串行代码中拆分或连接这两个实例是安全的。operator()也不能在同一个实例上并发调用。因此,文件必须真正说明:

当主体的操作符()或方法联接在不同的实例上同时运行时,它可以复制一个主体。

顺便说一句

parallel_reduce递归地将范围划分为子范围,以至于对于每个子区域,is_divisible()为false。

仅对simple_partitioner是正确的,对于其他分区,可以在到达is_divisible() == false之前停止拆分。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42973518

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档