OpenMP synchronization within the loop
c, openmp
Solution
You're trying to do two things - a computation and IO. The computation can be parallelized, but the IO must necessarily be serial. But by putting the IO in the same loop as the computation, you're forcing serialization on the computation as well, which makes no sense.
You'd be much better off doing all the computation, then doing the IO. This will almost certainly be faster even in serial, especially if you can write the data out in binary in one big chunk rather than with a loop over fprintfs.
FILE* f = fopen("output.txt", "w");
const int nIterations = 1000000;
int values[nIterations];
#pragma omp parallel for
for(int n=0; n<niterations; n++)
{
int a=0, b=0, c=0;
values[n] = do_computations(&a, &b, &c);
}
for (int n=0; n<niterations; n++)
fprintf(f,"%d\n", values[n]);
fclose(f);
This requires more memory, of course, but then speed vs memory is a common trade-off. If the extremes of that tradeoff don't work, you can always do the computation in adjustable-sized chunks:
const int nIterations = 1000000;
const int chunkSize = 10000;
int values[chunkSize];
int chunkNum = 0;
int chunkLeft = chunkSize;
for (int start = 0; start < nIterations; start+= chunkSize) {
if (start+chunkSize > nIterations) chunkLeft = nIterations - start;
#pragma omp parallel for
for(int n=start; n<start+chunkLeft; n++)
{
int a=0, b=0, c=0;
values[n-start] = do_computations(&a, &b, &c);
}
for (int n=0; n<chunkLeft; n++)
fprintf(f,"%d\n", values[n]);
}
fclose(f);
Problem
I have a large loop that generates data. Each iteration takes, say, 1 second and produces a chunk of data. I need all chunks written into the file in the correct order. If I just wanted to parallelize the loop, I could write something like this (highly simplified): ``` FILE* f = fopen("output.txt", "w"); omp_lock_t lock; omp_init_lock(&lock); int nIterations = 1000000; #pragma omp parallel for for(int thread=0; thread<4; thread++) { int a=0, b=0, c=0; for(int n=thread; n<nIterations; n+=4) { int value = do_computations(&a, &b, &c); omp_set_lock(&lock); fprintf(f, "%d\n", value); omp_unset_lock(&lock); } } #pragma omp barrier fclose(f); omp_destroy_lock(&lock); ``` This gets my output into the file, but the order of entries would not be guaranteed. I want to synchronize execution so that all threads do their tasks, then the master thread writes into the file, and then threads resume. In other words, I'd like something like this: ``` #pragma omp parallel for for(int thread=0; thread<4; thread++) { int a=0, b=0, c=0; int values[4]; for(int n=thread; n<nIterations; n+=4) { values[n] = do_computations(&a, &b, &c); #pragma omp barrier if(thread == 0) { for(int i=0; i<4; i++) fprintf(f, "%d\n", values[i]); } #pragma omp barrier } } #pragma omp barrier ``` Except, for some inexplicable reason, this is prohibited by the OpenMP specification. Or I could try ``` #pragma omp parallel for for(int thread=0; thread<4; thread++) { int a=0, b=0, c=0; for(int n=thread; n<nIterations; n+=4) { int value = do_computations(&a, &b, &c); #pragma omp ordered { fprintf(f, "%d\n", value); } } } #pragma omp barrier fclose(f); ``` But that won't work either, because "An iteration of a loop with a for construct ... must not execute more than one ordered directive." I don't want to rewrite the code as a single loop and I don't want to exchange loops. Is there a clean way to do this with OpenMP, without other threading/synchronization tools?