我正在尝试使用omp.h进行分布式搜索。我正在创建4个线程。id为0的线程不执行搜索,而是查询哪个线程在数组中找到了该数字。下面是我的代码:
int arr[15]; //This array is randomly populated
int process=0,i=0,size=15; bool found=false;
#pragma omp parallel num_threads(4)
{
int thread_id = omp_get_thread_num();
#pragma omp cancellation point parallel
if(thread_id==0){
while(found==false){ continue; }
if(found==true){
cout<<"Number found by thread: "<<process<<endl;
#pragma omp cancel parallel
}
}
else{
#pragma omp parallel for schedule(static,5)
for(i=0;i<size;i++){
if(arr[i]==number){ //number is a int variable and its value is taken from user
found = true;
process = thread_id;
}
cout<<i<<endl;
}
}
}
我的问题是,每个线程执行循环从i=0直到i=14。根据我的理解,omp划分了循环的迭代,但这里没有。谁能告诉我原因和可能的解决方案?
您的问题是您在parallel
中有parallel
。这意味着来自第一个并行区域的每个线程组成一个新团队。这被称为嵌套并行,它是允许的,但默认情况下它是关闭的。因此,每个线程创建一个由1个线程组成的团队,然后执行它的for循环部分,也就是整个循环。
所以你的omp parallel for
应该是omp for
。
但是现在有另一个问题:你的循环将分布在所有线程上,除了线程0永远不会到达循环。这样就会出现死锁
…这个问题的实际解要复杂得多。它涉及创建两个任务,一个在共享变量上旋转,另一个进行并行搜索。
#pragma omp parallel
{
# pragma omp single
{
int p = omp_get_num_threads();
int found = 0;
# pragma omp taskgroup
{
/*
* Task 1 listens to the shared variable
*/
# pragma omp task shared(found)
{
while (!found) {
if (omp_get_thread_num()<0) printf("spinn");
continue; }
printf("found!n");
# pragma omp cancel taskgroup
} // end 1st task
/*
* Task 2 does something in parallel,
* sets `found' to true if found
*/
# pragma omp task shared(found)
{
# pragma omp parallel num_threads(p-1)
# pragma omp for
for (int i=0; i<p; i++)
// silly test
if (omp_get_thread_num()==2) {
printf("two!n");
found = 1;
}
} // end 2nd task
} // end taskgroup
}
}
(你注意到从未执行过的printf了吗?我需要它来防止编译器"优化掉"。空while循环)
奖励解决方案:
#pragma omp parallel num_threads(4)
{
if(omp_get_thread_num()==0){ spin_on_found; }
if(omp_get_thread_num()!=0){
#pragma omp for nowait schedule(dynamic)
for ( loop ) stuff
dynamic
和nowait
的组合可以以某种方式处理缺失的线程。
-
@Victor Eijkhout已经解释了这里发生的事情,我只是想向您展示一个更简单(并且没有数据竞争)的解决方案。
-
请注意,OpenMP有一个显著的开销,在您的情况下,开销大于并行化的增益。因此,在这种情况下,最好不要使用并行化。
-
如果在循环中执行了一些开销较大的工作,最简单的解决方案是在不必要的情况下跳过这些开销较大的工作。注意,为了避免数据竞争,我在
found = true;
之前使用了#pragma omp critical
。
#pragma omp parallel for
for(int i=0; i<size;i++){
if(found) continue;
// some expensive work here
if(CONDITION){
#pragma omp critical
found = true;
}
}
- 另一种选择是使用
#pragma omp cancel for
#pragma omp parallel
#pragma omp for
for(int i=0; i<size;i++){
#pragma omp cancellation point for
// some expensive work here
if(CONDITION){
//cancelling the for loop
#pragma omp cancel for
}
}