3
\$\begingroup\$

What I basically want to do is this:

int main()
{
    const int n = 100;

    #pragma omp parallel for
    for (int i=0; i<n; i++)
    {
        int thread_ID = omp_get_thread_num();
        printf("%d) work 1 %d\n", thread_ID, i);
    #pragma omp barrier
        printf("    %d) work 2 %d\n", thread_ID, i);
    #pragma omp barrier
    }
    return 0;
}

except we cannot put a barrier into a parallel for in OpenMP; it just cannot be done. However, it's possible to explicitly do the separation between the threads in order to make it work:

#include <stdlib.h>
#include <stdio.h>
#include <omp.h>


int main()
{
    const int n = 100;
    int nthreads;
    #pragma omp parallel
    {
        // get the number of threads
        #pragma omp single
        {
            nthreads = omp_get_num_threads();
        }

        int thread_ID = omp_get_thread_num();

        // calculate which threads have to do one more iteration
        int one_more = thread_ID<(n%nthreads);
        int step = n/nthreads;
        int start, end;

        if(one_more){
            start = step*thread_ID + thread_ID;
            end = start + step + 1;
        }
        else{
            start = step*thread_ID + n%nthreads;
            end = start + step;
        }

        // the real work is here
        for (int i=start; i<start+step+1; i++)
        {
            if(i<end)
                printf("%d) work 1 %d\n", thread_ID, i);
        #pragma omp barrier
            if(i<end)
                printf("    %d) work 2 %d\n", thread_ID, i);
        #pragma omp barrier
        }

    }
    return 0;
}

However, I find this a bit dirty and I would have preferred something cleaner. Does somebody have a better idea?

\$\endgroup\$
2
  • \$\begingroup\$ What would the first program mean, if it meant something? barrier is used to ensure that the threads have all reached the same point in the code, but if that point is within a loop, threads may reach that point any number of times (including zero), and not necessarily the same number of times in all threads. Is the intent supposed to be that at any given time, work1 isn't being done at the same time as work2? It sounds like you just need a suitable mutex solution. Perhaps a bit more explanation of your motivation (use case) might help? \$\endgroup\$ Commented Apr 5, 2017 at 12:23
  • \$\begingroup\$ It would mean something if a barrier meant "all thread that did not terminate must reach this before continuing" and if it was allowed to put the barrier in the parallel loop obviously \$\endgroup\$
    – yakoudbz
    Commented Apr 5, 2017 at 13:25

1 Answer 1

3
\$\begingroup\$

You want to synchronize two parts of your iteration and parallelize the each one of them independently. A good option is splitting the code in two:

int main()
{
  const int n = 100;

  #pragma omp parallel
  {
  #pragma omp for
  for (int i=0; i<n; i++)
  {
      int thread_ID = omp_get_thread_num();
      printf("%d) work 1 %d\n", thread_ID, i);
  } // barrier (implicit, unless using 'nowait')

  #pragma omp for
  for (int i=0; i<n; i++)
  {
      printf("    %d) work 2 %d\n", thread_ID, i);
  } // barrier
  } // omp parallel
  return 0;
}
\$\endgroup\$
1
  • \$\begingroup\$ A really nice feature of this answer is that it will work the same way even if #pragma omp does nothing - which it could do if, for example, the code was compiled without the relevant compiler support flag such as -fopenmp. \$\endgroup\$ Commented Sep 8, 2023 at 4:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.