如何在OpenMP中使用锁?

33

我有两段运行在不同核心上的C++代码,它们都向同一个文件写入内容。

如何使用OpenMP并确保没有崩溃?

3个回答

67

您需要使用OMP_SET_LOCK/OMP_UNSET_LOCK函数: https://hpc.llnl.gov/tuts/openMP/#OMP_SET_LOCK

基本上:

omp_lock_t writelock;

omp_init_lock(&writelock);

#pragma omp parallel for
for ( i = 0; i < x; i++ )
{
    // some stuff
   omp_set_lock(&writelock);
    // one thread at a time stuff
    omp_unset_lock(&writelock);
    // some stuff
}

omp_destroy_lock(&writelock);

大多数锁定例程(如pthread信号量和sysv信号量)都基于这种逻辑,尽管特定的API调用有所不同。


40

为了方便后来者,使用critical是另一个选项。甚至可以创建命名的关键区域。

例如:

#include <omp.h>

void myParallelFunction()
{
    #pragma omp parallel for
    for(int i=0;i<1000;++i)
    {

        // some expensive work 

        #pragma omp critical LogUpdate
        {
            // critical section where you update file        
        }

        // other work

        #pragma omp critical LogUpdate
        {
            // critical section where you update file      
        }
    }
} 

编辑:评论区有一篇由Victor Eijkhout引发的很棒的帖子。概括和解释一下:简而言之,critical锁定了一个代码段。在更复杂的示例中,仅想锁定特定的数据项可能会过度使用它。在选择两种方法之间做出选择之前,理解这一点非常重要。


9
临界区锁定了一个代码段。如果您有成千上万次迭代并且只想确保没有两个线程同时执行相同的迭代,这并不是一个好主意。使用临界区意味着只有一个线程执行任何迭代。命名临界区稍微缓解了这个问题,但锁更加灵活,因为它们锁定数据元素而不是代码片段。 - Victor Eijkhout
1
@VictorEijkhout 抱歉,我不明白这个解决方案与@user257111的解决方案有何不同。在我看来,在此示例中用锁(lock)和解锁(unlock)替换#pragma omp critical将导致完全相同的代码,不是吗? - rph
1
这些是非常棒的要点,在我写这篇文章的时候我并不知道。我已经编辑了答案进行总结。 - Chris A.
关于关键区域和锁之间的区别:https://dev59.com/rl0b5IYBdhLWcg3wIOB9(答案说它们是相同的)。 - Cris Luengo
在VisualC++中,关键段的可选名称必须用括号括起来:https://learn.microsoft.com/en-us/cpp/parallel/openmp/reference/openmp-directives?view=msvc-170#critical - KungPhoo
显示剩余2条评论

19
#pragma omp critical
{
    // write to file here
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接