OpenMP编程的数据竞争问题

来源:互联网 发布:拨打电话变声软件 编辑:程序博客网 时间:2024/06/06 05:37

OpenMP编程的数据竞争问题

使用OpenMP编程时,通常都是将函数内的某段代码并行化执行,但是,对于在函数内声明的变量,很容易被多个线程同时读写访问,这将导致数据竞争问题。

不妨先看一个代码例子:

找出下面代码中的问题

template <class T>

void Parallel_Matrix_Sub(T *a, int row_a, int col_a, int as,  T *b, int bs, T *c, int cs)

{

int i, j;

int nCore = omp_get_num_procs();

#pragma omp parallel for num_threads(nCore)

for ( i = 0; i < row_a; i++ )

{

int row_i_a = i * as;

int row_i_b = i * bs;

int row_i_c = i * cs;

for ( j = 0; j < col_a; j++ )

{

//c[i][j] = a[i][j] - b[i][j]

c[row_i_c + j] = a[row_i_a + j] - b[row_i_b + j];

}

}

}

稍有经验的人就可以发现,上面代码中,j变量声明在OpenMP语句块的外面,因此,对各个线程来说,它是共享变量,OpenMP创建的多个线程都会访问j。内层循环中的j++可能会被多个线程同时执行,将导致程序运行出现无法预测的错误。改正后的代码如下:

template <class T>

void Parallel_Matrix_Sub(T *a, int row_a, int col_a, int as,  T *b, int bs, T *c, int cs)

{

int i;

const int nCore = omp_get_num_procs();

#pragma omp parallel for num_threads(nCore)

for ( i = 0; i < row_a; i++ )

{

int   j;

int row_i_a = i * as;

int row_i_b = i * bs;

int row_i_c = i * cs;

for ( j = 0; j < col_a; j++ )

{

//c[i][j] = a[i][j] - b[i][j]

c[row_i_c + j] = a[row_i_a + j] - b[row_i_b + j];

}

}

}

注意上面的代码中的加粗两行,变量j改为在内层循环内声明,这样创建线程时,变量j为每个线程的局部变量,不存在数据竞争问题。

对于const int nCore = omp_get_num_procs(); 这行,将变量nCore声明为

const类型后,后面的代码就无法对其进行写操作,可以避免线程内的代码对线程外的变量进行写操作,避免数据竞争问题。

根据上面的实例修改情况,可以归纳出两条避免OpenMP出现数据竞争的建议:

1.  尽量在并行循环内部申明局部变量

2.  对于并行循环外面的变量,尽量使用const类型,以保证在并行循环内不会发生写操作。对于没有使用const的变量,表明需要进行写操作,可以在检视代码时重点检视这些未使用const的变量是否用了锁或原子操作来进行保护。