我有5个函数A、B、C、D、E。
为了执行D,为了执行E,我需要执行A、D。
我试过这个
int main()
{
#pragma omp parallel num_threads(5)
{
long t1 = clock();
int a = 0, b = 0, c = 0, d = 0, e = 0;
int th = omp_get_thread_num();
if (th == 0) {
a += A();
printf("A is finished after %dn", clock() - t1);
}
if (th == 1) {
b += B();
printf("B is finished after %dn", clock() - t1);
}
if (th == 2) {
c += C();
printf("C is finished after %dn", clock() - t1);
}
if (th == 3 && (b == 1 && c == 1)) {
d += D();
printf("D is finished after %dn", clock() - t1);
}
if (th == 4 && (a == 1 && d == 1)) {
e += E();
printf("E is finished after %dn", clock() - t1);
}
}
return 0;
}
但D、E尚未执行
到目前为止,所有这些函数都返回1,用于调试
一个合适的OpenMP解决方案是使用具有数据依赖性的任务:
#pragma omp parallel num_threads(3)
#pragma omp single
{
double t1 = omp_wtime();
int a = 0, b = 0, c = 0, d = 0, e = 0;
#pragma omp task shared(a) depend(out: a)
{
a += A();
printf("A is finished after %fn", omp_wtime() - t1);
}
#pragma omp task shared(b) depend(out: b)
{
b += B();
printf("B is finished after %fn", omp_wtime() - t1);
}
#pragma omp task shared(c) depend(out: c)
{
c += C();
printf("C is finished after %fn", omp_wtime() - t1);
}
#pragma omp task shared(b,c,d) depend(in: b,c) depend(out: d)
{
d += D();
printf("D is finished after %fn", omp_wtime() - t1);
}
#pragma omp task shared(a,d,e) depend(in: a,d)
{
e += E();
printf("E is finished after %fn", omp_wtime() - t1);
}
}
这里,任务A
被标记为具有depend(out: a)
的a
的值的生产者,并且任务D
被标记为带有depend(out: d)
的d
的生产者。任务E
用depend(in: a,d)
标记为这两个值的使用者。根据输出(生产者(和输入(消费者(依赖关系,OpenMP运行时构建一个执行DAG(有向无环图(,"告诉"它所有任务的正确执行顺序。你也不需要五个线程——三个就足够了。
在single
构造中包含任务代码是非常惯用的OpenMP。
OpenMP 4.0早在2013年就引入了任务依赖性,因此除了MSVC++之外的任何现代编译器都应该支持该功能。
变量a
、b
、c
和d,
不能用于在线程之间通信,因为它们都是私有。因此,每个线程都有自己的私有副本。此外,将它们用于同步目的通常不是一个好主意。
在您的代码中,thread=3
永远不会在if (th == 3 && (b == 1 && c == 1))
上等待,因为:
b
和c
是私有的,因此无论其他线程对变量b=0
和c=0
的副本做了什么,thread=3
都有b=0
和c=0
- 没有 告诉线程等待(例如,一些类似同步的构造函数(
如果希望线程相互等待,请改用omp barrier
。所有线程都必须调用屏障,然后才能继续进行计算。
int main()
{
#pragma omp parallel num_threads(5)
{
long t1 = clock();
int a = 0, b = 0, c = 0, d = 0, e = 0;
int th = omp_get_thread_num();
if (th == 0) {
a += A();
printf("A is finished after %dn", clock() - t1);
}
if (th == 1) {
b += B();
printf("B is finished after %dn", clock() - t1);
}
if (th == 2) {
c += C();
printf("C is finished after %dn", clock() - t1);
}
// Threads will wait for each other here
#pragma omp barrier
if (th == 3) {
d += D();
printf("D is finished after %dn", clock() - t1);
}
// Threads will wait for each other here
#pragma omp barrier
if (th == 4) {
e += E();
printf("E is finished after %dn", clock() - t1);
}
}
return 0;
}
一种更复杂的方法是使用具有依赖性的任务,这是在OpenMP 4.0标准上发布的一项功能。关于这个功能如何在这个线程上工作,已经有了很好的解释。
int a = 0, b = 0, c = 0, d = 0, e = 0;
#pragma omp parallel num_threads(5) shared(a, b, c, d)
{
#pragma omp single nowait
{
long t1 = clock();
int th = omp_get_thread_num();
#pragma omp task depend (out:a)
{
a += A();
printf("A is finished after %dn", clock() - t1);
}
#pragma omp task depend (out:b)
{
b += B();
printf("B is finished after %dn", clock() - t1);
}
#pragma omp task depend (out:c)
{
c += C();
printf("C is finished after %dn", clock() - t1);
}
#pragma omp task depend (in:a, b) depend(out:d)
{
d += D();
printf("D is finished after %dn", clock() - t1);
}
#pragma omp task depend (in:a, b)
{
e += E();
printf("E is finished after %dn", clock() - t1);
}
}
}
return 0;
}