阻止多个线程只访问数组的一个元素(而不是整个数组)

时间:2015-05-04 16:55:05

标签: c multithreading openmp

我想计算一个二维浮点阵列' Image2D'并使用' OpenMP '更快地完成此操作在并行中执行外部for循环。

在循环中,位置' [jy] [jx]'在里面' Image2D'得到计算。因此,有可能在同一时刻,两个(或更多)线程想要增加' Image2D'在相同位置' [jy] [jx]'。在我理解的内容中(但你可以纠正我)在这种情况下只执行一个增量而另一个增量丢失。

为避免这种情况,我想添加一行代码' #pragma omp critical'。它确保只有一个线程可以读取/增加/写入变量' Image2D'。

不幸的是,这意味着当第一个线程正在访问' Image2D'时,其他线程必须等待,直到第一个线程完成其工作。对于我的代码,这将极大地减慢执行,因为' Image2D'随时访问。

此外' #pragma omp critical'是太严格:它会阻止多个线程访问整个数组' Image2D'虽然足以阻止访问一个元素的Image2D' (即一个位置' Image2D [jy] [jx]')。

所以,我的问题是:有办法吗?  (i)防止多个线程写入Image2D [jy] [jx]'同时; (ii)不让线程不必要地等待彼此,从而获得快速代码。

感谢您的回答

    #pragma omp parallel private(  ia, iR, Cte, jjx, jx,jy )
    {   // start parallel
    #pragma omp for
    for ( ia = i0a; ia <= i1a; ia++ ) {
            // ... code removed ....
            for ( iR = i0R; iR <= i1R; iR++ ) {
                    // ... code removed ....
                    // 'Cte' (float) and 'jjx' (float) are computed
                    for ( jy = j0y; jy <= j1y; jy++ ) {
                            // ... code removed ...
                            // 'jx' (int) gets computed
                            #pragma omp critical
                            Image2D[jy][jx] +=  Cte * (  1.0 - ( jjx - jx )  );     // increment 'Image2D[jy][jx]'
                            // ... code removed ....
                    } // Next 'jy'
            } // Next 'iR'
     }// Next 'ia'
     }// end parallel section

1 个答案:

答案 0 :(得分:0)

我不了解OpenMP,但听起来它并不能完全满足您的控制水平。

正如PetrH建议最好的答案可能是每个线程都有一个私有数组,然后再对这些数组求​​和。即便如此也可以并行化。

只要你有记忆,它就能很好地运作。如果不是,您可能需要考虑替代方案。这可能涉及互斥信号量。

显然,你的2D阵列足够大,需要OpenMP,因此每个单元的互斥量可能会浪费。每行可以有一个互斥锁,或者每10行一个,等等。互斥锁越少,两个线程争用同一组单元的机会就越大。此外,虽然您将在每次循环迭代时使用并提供互斥锁(并计算哪个互斥锁),但现在操作系统需要付出很多努力来快速进行互斥信号量系统调用。可能每个线程有一点额外的CPU时间可以为您提供所需的调度,因此总体效益可能会很好。