如何在cilk中跳出for循环?

How to break out of for loop in cilk?

for 循环如下所示:

cilk_for (int i=0; i<1000000; i++){
    do something;
    if(tag == 0){
        break;
    }
}

然后在编译时,我得到了这个错误:

error: break from parallel loop is not currently supported

您无法跳出 cilk_for,因为 cilk_for 不理解迭代顺序。 Cilk Plus(以及 TBB 和 OpenMP 等)中并行循环的迭代可以乱序同时执行 and/or。除非程序可以预测未来,否则如果第 100 次迭代在第 50 次执行之前或同时运行,第 100 次迭代如何知道第 50 次迭代有中断?

如果您确实需要在开始迭代 i+1 之前在迭代 i 退出循环,那么您的算法本质上是顺序的,您不能使用 cilk_for。但是,如果跳出循环是关于性能(做更少的工作)而不是正确性,那么您将遇到 class 个问题,称为 "speculative parallelism"。在推测并行中,您愿意为了并行的好处做一些额外的工作,但您尽量避免做太多额外的工作而失去并行的好处。

Cilk Plus 没有任何明确设计用于推测并行性的构造,但您可以相当轻松地编写一些代码。在这种情况下,最简单的事情是将 tag 变成循环外的原子变量并将条件更改为:

if (tag == 0)
    continue;

您可以使用顺序一致的内存排序写入 tag,但您可以选择使用宽松的内存排序来读取它以减少内存争用。专家领域通常会考虑宽松的内存排序,但在这种情况下,您的基础非常稳固。一个更复杂的系统将通过划分循环 space 并使用树结构在迭代中传播 "done" 标志来进一步减少内存争用。

请注意,如果您按照我上面的建议进行操作,那么 ALL 尚未完成的迭代将会看到变化,即使是那些按顺序会出现的迭代beforetag 设置为零的迭代。如果只想停止 后续 迭代,则不要更改 tag,而是使用单独的原子 stop_i 变量,并将逻辑更改为:

atomic_int stop_i(1000000);
cilk_for (int i=0; i<1000000; i++) {
    if (atomic_load(&stop_i, memory_order_relaxed) >= i)
        continue;
    do something;
    if(tag == 0){
        atomic_store(&stop_i, i, memory_order_seq_cst);
        continue;
    }
}

但是请注意,您仍然会在尝试的停止点之外进行许多迭代的推测执行。只有在您设置 stop_i 时尚未开始的迭代才会受到影响。