【问题标题】:Functions dependency openMP函数依赖 openMP
【发布时间】:2021-03-07 06:47:23
【问题描述】:

我有 5 个函数 A、B、C、D、E。

要执行 D,我需要执行 B、C, 要执行 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 %d\n", clock() - t1);
        }
        if (th == 1) {
            b += B();
            printf("B is finished after %d\n", clock() - t1);
        }
        if (th == 2) {
            c += C();
            printf("C is finished after %d\n", clock() - t1);
        }
        if (th == 3 && (b == 1 && c == 1)) {
            d += D();
            printf("D is finished after %d\n", clock() - t1);
        }
        if (th == 4 && (a == 1 && d == 1)) {
            e += E();
            printf("E is finished after %d\n", clock() - t1);
        }

    }
    return 0;
}

但是D、E还没有执行

到目前为止,所有这些函数都返回 1 用于调试目的

【问题讨论】:

    标签: c multithreading performance parallel-processing openmp


    【解决方案1】:

    变量abcd, 不能用于线程间通信,因为它们都是私有。因此,每个线程都有自己的私有副本。此外,将它们用于同步目的通常不是一个好主意。

    在您的代码中,thread=3 永远不会等待 if (th == 3 && (b == 1 && c == 1)),因为:

    1. bc 是私有的,所以 thread=3 具有 b=0c=0 而不管其他线程对变量 b=0c=0副本 做了什么.
    2. 什么都没有 告诉那个线程要等待(例如,一些类似同步的构造函数)。

    如果您希望线程相互等待,请改用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 %d\n", clock() - t1);
                }
                if (th == 1) {
                    b += B();
                    printf("B is finished after %d\n", clock() - t1);
                }
                if (th == 2) {
                    c += C();
                    printf("C is finished after %d\n", clock() - t1);
                }
                // Threads will wait for each other here
                #pragma omp barrier 
                if (th == 3) {
                    d += D();
                    printf("D is finished after %d\n", clock() - t1);
                }
                // Threads will wait for each other here
                #pragma omp barrier 
                if (th == 4) {
                    e += E();
                    printf("E is finished after %d\n", clock() - t1);
                }
            }
            return 0;
        }
    

    更复杂的方法是使用依赖于 OpenMP 4.0 标准上发布的功能的任务。关于这个功能在this thread.上的工作原理已经有了很好的解释

    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 %d\n", clock() - t1);
          }
          #pragma omp task depend (out:b) 
          {
             b += B();
             printf("B is finished after %d\n", clock() - t1);
          }
          #pragma omp task depend (out:c) 
          { 
              c += C();
              printf("C is finished after %d\n", clock() - t1);
          }
         #pragma omp task depend (in:a, b) depend(out:d) 
         {
            d += D(); 
            printf("D is finished after %d\n", clock() - t1);
         }
         #pragma omp task depend (in:a, b)  
         {
           e += E();
           printf("E is finished after %d\n", clock() - t1);
         }
      }
    }
    return 0;
    }
    

    【讨论】:

      【解决方案2】:

      适当的 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 %f\n", omp_wtime() - t1);
              }
              #pragma omp task shared(b) depend(out: b)
              {
                  b += B();
                  printf("B is finished after %f\n", omp_wtime() - t1);
              }
              #pragma omp task shared(c) depend(out: c)
              {
                  c += C();
                  printf("C is finished after %f\n", omp_wtime() - t1);
              }
              #pragma omp task shared(b,c,d) depend(in: b,c) depend(out: d)
              {
                  d += D();
                  printf("D is finished after %f\n", omp_wtime() - t1);
              }
              #pragma omp task shared(a,d,e) depend(in: a,d)
              {
                  e += E();
                  printf("E is finished after %f\n", omp_wtime() - t1);
              }
      
          }
      

      在这里,任务A 被标记为a 的值的生产者depend(out: a),任务D 被标记为d 的生产者depend(out: d)。任务Edepend(in: a,d) 标记为这两个值的消费者。在输出(生产者)和输入(消费者)依赖之后,OpenMP 运行时构建一个执行 DAG(有向无环图),告诉它所有任务的正确执行顺序。您也不需要五个线程 - 三个就足够了。

      single 结构中包含任务代码是非常惯用的 OpenMP。

      OpenMP 4.0 早在 2013 年就引入了任务依赖项,因此除 MSVC++ 之外的任何现代编译器都应提供对该功能的支持。

      【讨论】:

      • 你不需要依赖(out:d) 吗?
      • 以后不使用就不行了。
      • 好的,现在我明白你的意思了。
      • +1 感谢您的点击,顺便说一句,您真的需要在每个依赖项上添加共享,还是您可以在并行区域构造函数中定义写入?
      • ad 在我的解决方案中是私有的,所以是的,您需要明确共享它们,否则它们会在任务中变为 firstprivate。不是你的情况,因为它们在并行区域之外声明并且默认共享。
      猜你喜欢
      • 2017-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-12
      • 2013-06-16
      • 2020-04-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多