C++ 理解tbb::parallel_reduce的并发性

C++ 理解tbb::parallel_reduce的并发性,c++,concurrency,tbb,C++,Concurrency,Tbb,我使用的命令式形式是tbb::parallel\u reduce(range,body)as。医生说: 并行_reduce使用拆分构造函数为每个线程创建一个或多个主体副本。它可以在主体的运算符()或方法join同时运行时复制主体。您有责任确保此类并发的安全性 所以我知道Body::Body(Body&,split)可以作为Body::operator()或Body::join(Body&rhs)do运行 我的问题是: 1) Body::operator()和Body::join(Body&rhs

我使用的命令式形式是
tbb::parallel\u reduce(range,body)
as。医生说:

并行_reduce使用拆分构造函数为每个线程创建一个或多个主体副本。它可以在主体的运算符()或方法join同时运行时复制主体。您有责任确保此类并发的安全性

所以我知道
Body::Body(Body&,split)
可以作为
Body::operator()
Body::join(Body&rhs)
do运行

我的问题是

1)
Body::operator()
Body::join(Body&rhs)
可以同时运行吗

2) 能否安全地修改
rhs

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

struct Sum {
    float value;
    ...
    void operator()( const blocked_range<float*>& r ) {
        value = ...;
    }
    void join( Sum& rhs ) {value += rhs.value;}
};               
struct Sum{
浮动值;
...
void运算符()(常数阻塞的\u范围和r){
值=。。。;
}
void join(Sum&rhs){value+=rhs.value;}
};               

关于并发调用方法涉及哪些实例的文档不够清楚。但它暗示:

在典型使用中,安全无需额外努力

同一实例没有并发性。因此,像在串行代码中一样拆分或连接两个实例是安全的<代码>运算符()也不能在同一实例上同时调用。因此,文档必须真正说明:

当主体的操作符()或方法join在不同实例上并发运行时,它可能会复制主体

顺便说一句,报价

并行_reduce递归地将范围拆分为子范围,直到每个子范围的_divisible()为false`


仅对
simple\u partitioner
是正确的,对于其他分区器,它可以在到达
is\u divisible()==false

之前停止拆分。对于并发调用方法涉及的实例,文档不够清楚。但它暗示:

在典型使用中,安全无需额外努力

同一实例没有并发性。因此,像在串行代码中一样拆分或连接两个实例是安全的<代码>运算符()也不能在同一实例上同时调用。因此,文档必须真正说明:

当主体的操作符()或方法join在不同实例上并发运行时,它可能会复制主体

顺便说一句,报价

并行_reduce递归地将范围拆分为子范围,直到每个子范围的_divisible()为false`


仅对
simple\u partitioner
是正确的,对于其他分区器,它可以在达到
is\u divisible()==false
之前停止拆分
tbb::parallel\u reduce使用的
Body
对象的生存期为:

  • 它由拆分构造函数创建为另一个Body对象的“右”侧,然后更新为仅处理“左”侧
  • 运算符()
    应用于一个或多个后续范围
  • 它可以用作拆分新实体的构造函数的参数(是的,不止一次),并根据上面的#1进行更新
  • 它的方法
    join()
    是为#3中从中拆分的每个对象调用的
  • 它作为
    rhs
    连接回从中拆分的实体对象
  • 加入后会被销毁
  • 在上述操作中,#3可以同时运行到#2和#4;其余的都是顺序的,即使不一定由单个线程调用。换句话说,当一个实体为某些子范围积累部分缩减或连接另一个实体的结果时,它可以通过拆分新实体的构造函数来更新。这是可能需要保护的地方,但通常这些调用访问身体的不同部分

    因此,您的问题的答案是:

    1)
    Body::operator()
    Body::join(Body&rhs)
    可以同时运行吗

    否。
    join()
    仅在对
    operator()
    的所有调用之后才被调用,无论是对于
    this
    还是
    rhs

    2) 能否安全地修改
    rhs


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

    tbb::parallel\u reduce使用的
    主体
    对象的生存期是:

  • 它由拆分构造函数创建为另一个Body对象的“右”侧,然后更新为仅处理“左”侧
  • 运算符()
    应用于一个或多个后续范围
  • 它可以用作拆分新实体的构造函数的参数(是的,不止一次),并根据上面的#1进行更新
  • 它的方法
    join()
    是为#3中从中拆分的每个对象调用的
  • 它作为
    rhs
    连接回从中拆分的实体对象
  • 加入后会被销毁
  • 在上述操作中,#3可以同时运行到#2和#4;其余的都是顺序的,即使不一定由单个线程调用。换句话说,当一个实体为某些子范围积累部分缩减或连接另一个实体的结果时,它可以通过拆分新实体的构造函数来更新。这是可能需要保护的地方,但通常这些调用访问身体的不同部分

    因此,您的问题的答案是:

    1)
    Body::operator()
    Body::join(Body&rhs)
    可以同时运行吗

    否。
    join()
    仅在所有ca之后调用