【问题标题】:C++: OpenMP shared memory protectionC++:OpenMP 共享内存保护
【发布时间】:2012-06-14 05:37:49
【问题描述】:

如果我使用一个共享变量,比如说一个双精度变量,在程序执行过程中计算某种总和。无论如何,这是否容易受到不稳定操作的影响?我的意思是,是否有可能多个内核以异步方式访问该变量并导致不稳定的结果?

例如: 这是一个全局变量:

double totalTime = 0;

并且在每个核心中调用一个命令:

totalTime += elapsedTime;

最后一个操作/语句是通过取totalTime的值来执行的,把它放到CPU寄存器中,然后做加法。我可以想象多个核心会在同一时刻采用相同的值,然后添加新的 elapsedTime,然后由于延迟,存储在 totalTime 中的值将被错误的值覆盖。那可能吗?我该如何解决这个问题?

谢谢。

【问题讨论】:

    标签: c++ multithreading parallel-processing openmp shared-memory


    【解决方案1】:

    显然,此操作不是线程安全的,因为正如您自己提到的,它涉及多个汇编指令。事实上,openMP 甚至对这类操作都有专门的指令。

    您将需要atomic pragma 来使其成为“原子”:

    #pragma omp atomic
    totalTime += elapsedTime;
    

    请注意,atomic 仅在您对内存位置进行单次更新(如加法、增量等)时才有效。

    如果您有一系列指令需要原子在一起,您必须使用critical 指令:

    #pragma omp critical
    {
        // atomic sequence of instructions
    }
    

    编辑:这里有一个来自“snemarch”的好建议:如果您在并行循环中反复更新全局变量totalTime,您可以考虑使用reduction 子句来自动化该过程并也让它更有效率:

    double totalTime = 0;
    
    #pragma omp parallel for reduction(+:totalTime)
    for(...)
    {
        ...
        totalTime += elapsedTime;
    }
    

    最后totalTime 将正确包含本地elapsedTime 值的总和,而无需显式同步。

    【讨论】:

    • 我想知道 OpenMP 如何支持 x86 上浮点数据类型的原子添加 - 它没有本机指令。关键部分?
    • @snemarch:我找不到任何关于它的确切信息,所以我猜它使用了锁。
    • 顺便说一句,编译器无法识别关键字 atomic。 g++ 忽略它并且英特尔编译器给出错误。我决定改用 omp critical。
    • 很奇怪...你收到什么信息?
    • 请记住,关键部分很慢 - 取决于您的代码的其余部分,如果您可以使用每个线程变量,然后在线程完成后组合这些结果,则可能值得研究。不过,不知道如何用 OMP 表达这一点:)
    猜你喜欢
    • 2012-02-09
    • 2014-02-07
    • 2012-07-05
    • 2011-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-27
    • 1970-01-01
    相关资源
    最近更新 更多