我使用命令式的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文档中的示例,很明显,它们可以修改相同的数据,而不会出现数据争用问题:
struct Sum {
float value;
...
void operator()( const blocked_range<float*>& r ) {
value = ...;
}
void join( Sum& rhs ) {value += rhs.value;}
}; 发布于 2017-03-25 23:28:07
Body对象由tbb::parallel_reduce使用的生存期为:
operator()应用于一个或多个后续范围。join()是为#3中从它分割的每个对象调用的。rhs的形式加入到它被拆分的body对象中。在上面的操作中,#3可以并发运行到#2和#4;其余操作都是连续的,即使不一定由单个线程调用。换句话说,当一个主体为某个子区间积累部分约简或加入另一个体的结果时,它可以通过拆分新体的构造函数来更新。这是可能需要保护的地方,但通常情况下,这些呼叫会访问身体的不同部分。
所以,你的问题的答案是:
1)
Body::operator()和Body::join( Body& rhs )能否同时运行?
不是的。join()只会被调用到operator(),包括this和rhs。
2)
Body::join( Body& rhs )能安全地修改rhs吗?
是的,它可以。但是,除了可能在联接期间移动其内容并相应地更新状态外,修改rhs没有什么意义,因为它将在join()调用之后立即销毁。
发布于 2017-03-23 22:55:06
对于在并发调用方法中涉及哪些实例,文档还不够清楚。但它暗示:
在典型的使用中,安全不需要额外的努力。
同一实例没有并发性。因此,在串行代码中拆分或连接这两个实例是安全的。operator()也不能在同一个实例上并发调用。因此,文件必须真正说明:
当主体的操作符()或方法联接在不同的实例上同时运行时,它可以复制一个主体。
顺便说一句
parallel_reduce递归地将范围划分为子范围,以至于对于每个子区域,is_divisible()为false。
仅对simple_partitioner是正确的,对于其他分区,可以在到达is_divisible() == false之前停止拆分。
https://stackoverflow.com/questions/42973518
复制相似问题