B5 - parallel for
#pragma omp parallel for
for (i = i_start; i <= i_end; inc_exp) {
// statements
}
-
this creates a work-sharing construct, and also shares work
-
the loop index is private by default
-
the loop must not have any early exit statements (
break, butcontinueis allowed) -
it must have a single entry point at the top and a single exit point at the bottom
-
the index start and end values must not change during the loop
-
increment expressions only change
iby a fixed amount each iteration -
orderedclauses can be used, which make each thread wait until the previous iteration has finished its ordered section before doing its own
#pragma omp parallel for ordered
for (i=0; i<n; i++) {
a[i] = costly_func(i);
#pragma omp ordered
printf("%d %f\n", i, a[i])
}
- only loops in which there is no data-dependence on another iteration can be parallelised using this
// cannot parallelise
for (i=1; i<n; i++) {
a[i] = a[i] = a[i-1]; // depends on previous iteration
}
// can parallelise
for (i=1; i<n; i+=2) { // only odd indices are modified
a[i] = a[i] = a[i-1]; // data-dependence on even (uniterated) indices
}
last/first private
int x = 10;
#pragma omp parallel private(x)
{
printf("Thread %d: x = %d\n",
omp_get_thread_num(), x);
}
- in the above code, each thread gets an independent, uninitialized copy of
x
int x = 10;
#pragma omp parallel firstprivate(x)
{
printf("Thread %d: x = %d\n",
omp_get_thread_num(), x);
x += omp_get_thread_num();
}
printf("Original x = %d\n", x);
- here, each thread gets an independent, initialised copy
- the original value remains unchanged, so after the parallel construct,
x = 10
int x = 10;
#pragma omp parallel for lastprivate(x)
for (int i = 0; i < 4; i++) {
x = i * 10;
}
printf("x = %d\n", x);
- now, the last logical iteration's value is copied
- the output will be
10