SCOPE OF VARIABLES
In serial programming, the scope of a variable consists of those parts of a program in which the variable can be used. For example, a variable declared at the beginning of a C function has “function-wide” scope, that is, it can only be accessed in the body of the function. On the other hand, a variable declared at the beginning of a .c file but outside any function has “file-wide” scope, that is, any function in the file in which the variable is declared can access the variable. In OpenMP, the scope of a variable refers to the set of threads that can access the variable in a parallel block. A variable that can be accessed by all the threads in the team has shared scope, while a variable that can only be accessed by a single thread has private scope.
In the “hello, world” program, the variables used by each thread (my rank and thread count) were declared in the Hello function, which is called inside the parallel block. Consequently, the variables used by each thread are allocated from the thread’s (private) stack, and hence all of the variables have private scope. This is almost the case in the trapezoidal rule program; since the parallel block is just a function call, all of the variables used by each thread in the Trap function are allocated from the thread’s stack.
However, the variables that are declared in the main function (a, b, n, global_result, and thread count) are all accessible to all the threads in the team started by the parallel directive. Hence, the default scope for variables declared before a parallel block is shared. In fact, we’ve made implicit use of this: each thread in the team gets the values of a, b, and n from the call to Trap. Since this call takes place in the parallel block, it’s essential that each thread has access to a,b, and n when their values are copied into the corresponding formal arguments.
Furthermore, in the Trap function, although global result p is a private vari-able, it refers to the variable global result which was declared in main before the parallel directive, and the value of global result is used to store the result that’s printed out after the parallel block. So in the code
*globa_l result p += my_result;
it’s essential that global result p have shared scope. If it were private to each thread, there would be no need for the critical directive. Furthermore, if it were private, we would have a hard time determining the value of global result in main after completion of the parallel block.
To summarize, then, variables that have been declared before a parallel direc-tive have shared scope among the threads in the team, while variables declared in the block (e.g., local variables in functions) have private scope. Furthermore, the value of a shared variable at the beginning of the parallel block is the same as the value before the block, and, after completion of the parallel block, the value of the variable is the value at the end of the block.
We’ll shortly see that the default scope of a variable can change with other directives, and that OpenMP provides clauses to modify the default scope.