OpenMP: Shared and Private Variables

Hey guys! Welcome to HPC education and today we’ll be looking at private and shared variables. A variable in an OpenMP parallel region can be either shared or private. If a variable is shared, then there exists one instance of this variable which is shared among all threads. If a variable is private, then each thread in a team of threads has its own local copy of the private variable. OpenMP has a set of rules, which deduce the data-sharing attributes of variables. For example, let us consider the following snippet of code. There are four variables i, n, a and b. The data-sharing attribute of variables, which are declared outside the parallel region, is usually shared. Therefore, n and a are shared variables. The loop iteration variables, however, are private by default. Therefore, i is private. The variables which are declared locally within the parallel region are private. Thus b is private. It is better to declare the loop iteration variables inside the parallel region. Here is how that looks. We can explicitly set the data-sharing attribute of a variable. Let’s look at the shared clause first. The shared(list) clause declares that all the variables in list are shared. Here, n and a are shared variables. But always remember that shared variables introduce an overhead, because one instance of a variable is shared between multiple threads. Therefore, it is often best to minimize the number of shared variables when good performance is desired. The private(list) clause declares that all the variables in list are private. b is a private variable. When a variable is declared private, OpenMP replicates this variable and assigns its local copy to each thread. On several occasions, we can avoid listing private variables in the OpenMP constructs by declaring them inside a parallel region. For example, instead of this, we can do this. It is better to declare private variables inside a parallel region whenever possible. This guideline simplifies the code and increases its readability. There are two versions of the default clause. First, we focus on default(shared) option. The default(shared) clause sets the data-sharing attributes of all variables in the construct to shared. Here a, b, c and n are shared variables. In this snippet we see another usage of default(shared) clause which is to specify the data-sharing attributes of the majority of the variables and then additionally define the private variables. The default(none) clause forces a programmer to explicitly specify the data-sharing attributes of all variables. Lets execute the following code. The output shows an error. This is because we used default(none) clause and then forgot to explicitly specify the data-sharing attribute of a. The corrected code would be… Some key points to remember are: always write parallel regions with the default(none) clause. This forces the programmer to explicitly think about the data-sharing attributes of all variables. And always declare private variables inside parallel regions whenever possible. This guideline improves the readability of the code and makes it clearer.