1

I have 5 functions A,B,C,D,E.

To execute D I need B, C to be executed, to execute E I need A, D to be executed.

I have tried this

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;
}

but D, E haven't execute

All of these functions return 1 till now for debugging purpose

dreamcrash
  • 47,137
  • 25
  • 94
  • 117

2 Answers2

2

A proper OpenMP solution would be to use tasks with data dependencies:

    #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);
        }

    }

Here, task A is marked as producer for the value of a with depend(out: a) and task D is marked as the producer of d with depend(out: d). Task E is marked as consumer of those two values with depend(in: a,d). Following the output (producer) and input (consumer) dependencies, the OpenMP runtime builds an execution DAG (directed acyclic graph) that tells it the proper order of execution of all the tasks. You also don't need five threads - three are enough.

Having the tasking code inside a single construct is very idiomatic OpenMP.

Task dependencies were introduced by OpenMP 4.0 back in 2013, so any modern compiler except MSVC++ should provide support for that feature.

Hristo Iliev
  • 72,659
  • 12
  • 135
  • 186
1

The variables a, b, c and d, cannot be used to communicate among threads because they are all private. Hence, each thread has its own private copy of them. Moreover, it is normally not a good idea to use them for synchronization purposes.

In your code thread=3 would never wait on if (th == 3 && (b == 1 && c == 1)) because:

  1. b and c are private, so thread=3 has b=0 and c=0 regardless of what the other threads have done to their copies of the variables b=0 and c=0.
  2. There is nothing telling that thread to wait (e.g., some synchronization-alike constructor).

If you want threads to wait for each other use the omp barrier instead. All threads will have to call the barrier before they can proceed with their computation.

 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;
    }

A more sophisticated approach would be to use tasks with dependencies a feature released on the OpenMP 4.0 standard. There is already a nice explanation about how this feature works on 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;
}
dreamcrash
  • 47,137
  • 25
  • 94
  • 117