【问题标题】:How to break out of for loop in cilk?如何打破cilk中的for循环?
【发布时间】:2023-03-13 02:30:01
【问题描述】:

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


    【解决方案1】:

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

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

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

    if (tag == 0)
        continue;
    

    您可以使用顺序一致的内存顺序写入tag,但您可以选择使用宽松的内存顺序读取它以减少内存争用。放松的记忆排序通常在专家的范围内被考虑,但在这种情况下,你的基础非常稳固。更复杂的系统将通过划分循环空间并使用树结构在迭代中传播“完成”标志来进一步减少内存争用。

    请注意,如果您按照我上面的建议进行操作,那么 ALL 尚未完成的迭代将会看到变化,即使是那些依次之前 将tag 设置为零的迭代。如果您只想停止后续次迭代,则不要更改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 时尚未开始的迭代才会受到影响。

    【讨论】:

    • 这真的很有帮助。我将 for 循环中的条件更改为 break。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-11
    • 1970-01-01
    相关资源
    最近更新 更多