【问题标题】:OpenMP conditional criticalOpenMP 条件临界
【发布时间】:2017-10-20 13:20:04
【问题描述】:

首先,请记住,我不是 OpenMP 的频繁用户...好吗?

现在我们已经过去了,还有条件 critical 这样的东西吗?
我对并行化 for 循环中的这条线特别感兴趣:

(...)

    #pragma omp critical
    myMapOfVectors[i].push_back(someNumber);

(...)

我想要它critical当且仅当运行此特定行的线程具有相同的i(因为正如我所经历的那样 - 如果我错了——多个线程推回到同一个vector 不是线程安全的,可能会导致segfault)。

【问题讨论】:

    标签: c++ multithreading openmp


    【解决方案1】:

    您需要为每个索引i 提供一个lock

    // before you parallel region
    std::vector<omp_lock_t> myLocks(myMapOfVectors.size());
    for (size_t i = 0; i < myLocks.size(); ++i) {
        omp_init_lock(myLocks+i);
    }
    
    ...
    
    omp_set_lock(myLocks[i]);
    myMapOfVectors[i].push_back(someNumber);
    omp_unset_lock(myLocks[i]);
    
    ...
    
    // after your parallel region
    for (size_t i = 0; i < myLocks.size(); ++i) {
        omp_destroy_lock(myLocks+i);
    }
    

    关键部分本质上只是一个锁,通过拥有多个锁,您实质上是在模拟为每个索引设置一个单独的关键部分。

    请记住,锁定可能会很慢(尤其是在发生冲突时)。如果您可以提前对您的工作进行分区(即,每个线程在不同的索引集i 上工作,或者每个线程都有自己的myMapOfVectors 副本,稍后合并),您可能能够获得更好的性能。

    【讨论】:

    • 感谢您的回答!我喜欢你的解决方案,但我希望有一些指令可以为我完成繁重的工作。我的意思是,这就是我们拥有 OpenMP 的原因,不是吗? :P 不是对你的抱怨,只是对 OpenMP 的批评......
    • 因为编译指示是编译时指令,它们不能用于同步动态分配的堆对象(至少在一般情况下)。如果您实现自己的堆栈对象(具有固定的内存分配),您可以使用#pragma omp atomic 在内部插入元素(插入不会是原子的,但会增加计数)。
    【解决方案2】:

    查看我的回答here。您可以派生 std::vector 类来实现合适的 atomic_push_back 方法。

    你的示例代码可以写成

    std::vector<omp_vector<...>> myMapOfVectors;
    (...)
    
        myMapOfVectors[i].atomic_push_back(someNumber);
    
    (...)
    

    不需要任何关键区域。请注意,内部锁仅在不同线程推回相同的第 i 个 omp_vector 时才起作用

    【讨论】:

      猜你喜欢
      • 2016-05-12
      • 2014-12-08
      • 1970-01-01
      • 2015-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多