C++ 在同一线程上运行的所有OpenMP任务
我用OpenMP中的任务编写了一个递归并行函数。虽然它给了我正确的答案并且运行良好,但我认为并行性存在一个问题。与串行解决方案相比,运行时在我没有任务的情况下解决的其他并行问题中无法扩展。打印任务的每个线程时,它们都在线程0上运行。我正在Visual Studio Express 2013上编译和运行C++ 在同一线程上运行的所有OpenMP任务,c++,multithreading,task,openmp,C++,Multithreading,Task,Openmp,我用OpenMP中的任务编写了一个递归并行函数。虽然它给了我正确的答案并且运行良好,但我认为并行性存在一个问题。与串行解决方案相比,运行时在我没有任务的情况下解决的其他并行问题中无法扩展。打印任务的每个线程时,它们都在线程0上运行。我正在Visual Studio Express 2013上编译和运行 int parallelOMP(int n) { int a, b, sum = 0; int alpha = 0, beta = 0; for (int k = 1;
int parallelOMP(int n)
{
int a, b, sum = 0;
int alpha = 0, beta = 0;
for (int k = 1; k < n; k++)
{
a = n - (k*(3 * k - 1) / 2);
b = n - (k*(3 * k + 1) / 2);
if (a < 0 && b < 0)
break;
if (a < 0)
alpha = 0;
else if (p[a] != -1)
alpha = p[a];
if (b < 0)
beta = 0;
else if (p[b] != -1)
beta = p[b];
if (a > 0 && b > 0 && p[a] == -1 && p[b] == -1)
{
#pragma omp parallel
{
#pragma omp single
{
#pragma omp task shared(p), untied
{
cout << omp_get_thread_num();
p[a] = parallelOMP(a);
}
#pragma omp task shared(p), untied
{
cout << omp_get_thread_num();
p[b] = parallelOMP(b);
}
#pragma omp taskwait
}
}
alpha = p[a];
beta = p[b];
}
else if (a > 0 && p[a] == -1)
{
#pragma omp parallel
{
#pragma omp single
{
#pragma omp task shared(p), untied
{
cout << omp_get_thread_num();
p[a] = parallelOMP(a);
}
#pragma omp taskwait
}
}
alpha = p[a];
}
else if (b > 0 && p[b] == -1)
{
#pragma omp parallel
{
#pragma omp single
{
#pragma omp task shared(p), untied
{
cout << omp_get_thread_num();
p[b] = parallelOMP(b);
}
#pragma omp taskwait
}
}
beta = p[b];
}
if (k % 2 == 0)
sum += -1 * (alpha + beta);
else
sum += alpha + beta;
}
if (sum > 0)
return sum%m;
else
return (m + (sum % m)) % m;
}
intparallecomp(intn)
{
int a,b,和=0;
int alpha=0,beta=0;
对于(int k=1;k0&&b>0&&p[a]=-1&&p[b]=-1)
{
#pragma-omp并行
{
#布拉格omp单曲
{
#pragma omp任务共享(p),未绑定
{
cout实际问题:
您正在使用Visual Studio 2013
Visual Studio从未支持2.0以上的OMP版本(请参阅)
OMP任务是OMP 3.0的一项功能(请参阅)
因此,使用VS意味着你没有OMP任务
如果OMP任务是一个基本的要求,使用不同的编译器。如果OMP不是一个基本的要求,你应该考虑一个可替代的并行任务处理库。VisualStudio包括MS并发运行时,以及它的内置。我最近从OMP转移到PPL,因为我用VS工作,它不是退出。e替代品数量减少,但功能相当强大
我第二次尝试解决这个问题,也是出于历史原因而保留下来的:
因此,问题几乎可以肯定,您正在omp并行
区域之外定义omp任务
下面是一个人为的例子:
void work()
{
#pragma omp parallel
{
#pragma omp single nowait
for (int i = 0; i < 5; i++)
{
#pragma omp task untied
{
std::cout <<
"starting task " << i <<
" on thread " << omp_get_thread_num() << "\n";
sleep(1);
}
}
}
}
但是如果你把它留在里面:
starting task starting task 3 on thread 1
starting task 0 on thread 3
2 on thread 0
starting task 1 on thread 2
starting task 4 on thread 2
成功,完成共享输出资源的真实滥用
(作为参考,如果省略单个
声明,每个线程将运行循环,导致在我的4 cpu虚拟机上运行20个任务)
为完整起见,以下包含原始答案,但不再相关!
在任何情况下,您的omp任务都是一件简单的事情。它可能会立即运行并完成:
#pragma omp task shared(p), untied
cout << omp_get_thread_num();
#pragma omp task shared(p), untied
cout << omp_get_thread_num();
#pragma omp task shared(p), untied
cout << omp_get_thread_num();
#pragma omp task shared(p), untied
cout << omp_get_thread_num();
#pragma omp任务共享(p),未绑定
cout有时我希望对SO的评论可以像答案一样格式丰富,但遗憾的是事实并非如此。因此,这里有一个伪装成答案的长评论
看来,编写递归OpenMP代码的一个非常常见的错误是不理解并行区域是如何工作的。考虑下面的代码(使用显式任务,因此支持OpenMP 3或更新所需的):
一旦启用嵌套并行,就会面临一个新问题。每次遇到嵌套并行区域时,遇到的线程都会生成一个额外的线程(因为num_threads(2)
)或者从运行时的线程池中获取一个空闲线程。在每一个更深层次的递归中,此程序将需要两倍于上一层次的线程。尽管可以通过OMP\u thread\u limit
设置线程总数的上限(另一个OpenMP 3.0功能)撇开开销不谈,在这种情况下,这并不是人们真正想要的
在这种情况下,正确的解决方案是在单个并行区域的动态范围内使用孤立任务:
void par_rec_func (int arg)
{
if (arg <= 0) return;
#pragma omp task
par_rec_func(arg-1);
#pragma omp task
par_rec_func(arg-1);
// Wait for the child tasks to complete if necessary
#pragma omp taskwait
}
// somewhere in the main function
#pragma omp parallel
{
#pragma omp single
par_rec_func(10);
}
omp\u get\u level()
用于确定嵌套级别,而if
子句用于在嵌套的第四级或更深层有选择地停用并行区域。此解决方案是愚蠢的,在递归树不平衡时无法正常工作。是的,这就是我想要做的,但它仍然会产生相同的问题。@BenMcAlindin请修复此问题那么,他在你的问题中编写了代码。这很有意义(虽然我的课堂讲稿中没有),但仍然不起作用。我尝试将并行语句和单个语句放在几个地方:在每个任务之前,在parallecomp()的开头,在main()中调用parallecomp()之前我更新了代码,以显示在每个task@BenMcAlindin我自己组装了一个最小的示例,通过在omp parallel
区域内调用parallelOMP
,我得到了(如预期的那样)显示在不同线程上运行的任务的结果。也许您应该使用一个非常基本的OMP示例检查您是否启用了OMP,并且它正在运行,并且它可以访问多个内核。您能告诉我们哪个编译器(和版本)吗您正在使用以及如何构建可执行文件?宝贵的经验教训:永远不要假设其他人知道MS的最小OMP支持,并且始终询问OP他们首先使用的编译器;-)
if (a > 0 && b > 0 && p[a] == -1 && p[b] == -1)
{
#pragma omp task shared(p), untied
{
cout << omp_get_thread_num();
p[a] = parallelOMP(a);
}
#pragma omp task shared(p), untied
{
cout << omp_get_thread_num();
p[b] = parallelOMP(b);
}
#pragma omp taskwait
alpha = p[a];
beta = p[b];
}
void par_rec_func (int arg)
{
if (arg <= 0) return;
#pragma omp parallel num_threads(2)
{
#pragma omp task
par_rec_func(arg-1);
#pragma omp task
par_rec_func(arg-1);
}
}
// somewhere in the main function
par_rec_func(10);
omp_set_nested(1);
void par_rec_func (int arg)
{
if (arg <= 0) return;
#pragma omp task
par_rec_func(arg-1);
#pragma omp task
par_rec_func(arg-1);
// Wait for the child tasks to complete if necessary
#pragma omp taskwait
}
// somewhere in the main function
#pragma omp parallel
{
#pragma omp single
par_rec_func(10);
}
void par_rec_func (int arg)
{
if (arg <= 0) return;
int level = omp_get_level();
#pragma omp parallel sections num_threads(2) if(level < 4)
{
#pragma omp section
par_rec_func(arg-1);
#pragma omp section
par_rec_func(arg-1);
}
}
// somewhere in the main function
int saved_nested = omp_get_nested();
omp_set_nested(1);
par_rec_func(10);
omp_set_nested(saved_nested);