我有一个函数,我们叫它dostuff()
,它有时对我的应用程序并行化是有益的,或者多次并行化整个东西。该函数在两个用例之间不会改变。
注意:object
足够大,不能存储在列表中,因此每次迭代都必须丢弃它。
我们的代码是这样的:
bool parallelize_within = argv[1];
if (parallelize_within) {
// here we assume parallelization is handled within the function dostuff()
for (int i = 0; i < 100; ++i) {
object randomized = function_that_accesses_rand();
dostuff(i, randomized, parallelize_within);
}
} else {
#pragma omp parallel for
for (int i = 0; i < 100; ++i) {
object randomized = function_that_accesses_rand();
dostuff(i, randomized, parallelize_within);
}
}
显然,我们遇到了dostuff()
会让线程在同一程序的不同迭代中在不同时间访问随机对象的问题。这不是parallelize_within == true
时的情况,但是当我们并行运行dostuff()
时,每个线程单独运行,是否有一种方法可以保证随机对象是根据迭代顺序访问的?我知道我能做到:
#pragma omp parallel for schedule(dynamic)
将保证最终,当迭代在运行时动态地分配给线程时,对象将按照迭代号的顺序访问rand,但对于第一组迭代,它将完全随机。对于如何避免这种情况有什么建议吗?
-
首先你必须确保
function_that_accesses_rand
和do_stuff
都是线程安全的。 -
如果你使用
if
子句,你不必复制你的代码:#pragma omp parallel for if(!parallelize_within)
-
要确保在
dostuff(i, randomized,...);
i
函数中反映randomized
对象的创建顺序,您必须这样做:
int j = 0;
#pragma omp parallel for if(!parallelize_within)
for (int i = 0; i < 100; ++i) {
int k;
object randomized;
#pragma omp critical
{
k = j++;
randomized = function_that_accesses_rand();
}
dostuff(k, randomized, parallelize_within);
}
- 如果您的
function_that_accesses_rand
使其成为可能,您可以消除critical
部分的使用,但在不了解您的功能的情况下,我无法更具体。一种解决方案是,该函数返回表示订单的值。不要忘记这个函数必须是线程安全的!
#pragma omp parallel for if(!parallelize_within)
for (int i = 0; i < 100; ++i) {
int k;
object randomized = function_that_accesses_rand(k);
dostuff(k, randomized, parallelize_within);
}
... function_that_accesses_rand(int& k){
...
#pragma omp atomic capture
k = some_internal_counter++;
...
}
您可以预先生成随机对象并将其存储在列表中。然后在omp循环中添加一个变量,每个线程增加一个。
// generate random objects
i=0
#pragma omp parallel for
for( ... ){
do_stuff(...,rand_obj[i],...)