In the previous article, we gave a recommendation to use the default(none) clause whenever possible.

The default(none) clause forces a programmer to explicitly specify the data-sharing attributes of all variables in a parallel region. Using this clause then forces the programmer to think about data-sharing attributes.

This is beneficial because the code is clearer and has less bugs.

But following this principle might be difficult in some cases. In the next example,

const int n = 10;
const int a = 7;

#pragma omp parallel for default(none) shared(a, n)
for (int i = 0; i < n; i++)
{
    int b = a + i;
    ...
}

we list a and n in the shared clause, because they are shared variables.

Unfortunately, the gcc compiler does not compile the code. The compiler terminates with the following compilation error.

$ g++ -fopenmp -Wall -pthread ompDefaultNone.cpp -o ompDefaultNone
In function "int main()":
error: "a" is predetermined "shared" for "shared"
#pragma omp parallel for default(none) shared(a, n)

The same happens with the versions 4.8.4, 4.9.3, 5.3.0 and 6.1.1 of the gcc compiler. They all give the same error.

So, what is happening?

The variables a and n are const variables. Since they can not be modified, the compiler implicitly sets their data-sharing attribute to shared. This makes sense, because there is arguably no need to make a private copy of a constant variable for each thread.

Then we, as programmers, explicitly set the data-sharing attribute of the const variables to shared. We do it by listing the variables in the shared clause.

Here the problem happens.

The compiler complains that we set the data-sharing attribute of a to shared, but its data-sharing attribute was already predetermined to be shared. This is what the compiler wants to tell us with:

error: "a" is predetermined "shared" for "shared"

It looks like that the compiler does not accept explicit information about the data-sharing attribute when the compiler knows it already.

The solution is to omit the const variables from the shared clause (because their data-sharing attribute is already determined) and to still use the default(none) clause (because of its benefits).

Then, the solution of the previous example looks like this:

const int n = 10;
const int a = 7;

#pragma omp parallel for default(none) 
for (int i = 0; i < n; i++)
{
    int b = a + i;
    ...
}

Now, the code compiles. The const variables are shared inside the parallel region and we still have the benefits of the default(none) clause for the non-const variables.

Summary

In this article, we addressed a problem with the default(none) clause and const variables. We also presented a solution to the problem.

Link:

Jaka’s Corner OpenMP series: