By ``global variables'', we mean anything that is stored at a fixed,
preallocated location in memory. In C, this means variables declared
at file scope or with the static keyword. In Fortran, this is
either variables that are part of a COMMON block, declared inside
a MODULE or variables with the SAVE attribute.
Global variables are shared by all the threads on a processor, which
makes using global variables extremely error prone.
To see why this is a problem, consider a program fragment like:
foo=a
call MPI_Recv(...)
b=foo
After this code executes, we might expect b to always be equal to a.
but if foo is a global variable, MPI_Recv may block and
foo could be changed by another thread.
For example, if two threads execute this program, they could interleave like:
Thread 1
Thread 2
foo=1
block in MPI_Recv
foo=2
block in MPI_Recv
b=foo
At this point, thread 1 might expect b to be 1; but it will actually be 2.
From the point of view of thread 1, the global variable foo suddenly
changed its value during the call to MPI_Recv.
There are several possible solutions to this problem:
Never use global variables--only use parameters or local variables.
This is the safest and most general solution.
One standard practice is to collect all the globals into a C struct or
Fortran type named ``Globals", and pass a pointer to this object to all
your subroutines. This also combines well with the pup method for doing
migration-based load balancing, as described in Section 3.1.
Never write different values to global variables. If every thread
writes the same value, global variables can be used safely. For example,
you might store some parameters read from a configuration file like the
simulation timestep . See Section 3.2
for another, more convenient way to set such variables.
Never issue a blocking call while your global variables are set.
This will not work on a SMP version of Charm++, where several processors
may share a single set of global variables.
Even on a non-SMP version, this is a dangerous solution, because someday
someone might add a blocking call while the variables are set.
This is only a reasonable solution when calling legacy code or
using old serial libraries that might use global variables.
The above only applies to routines that run in the parallel context.
There are no restrictions on global variables for serial context
code.