Initialization of each copy, if any, is done before the first reference to that copy, typically when the private
copy of the threadprivate data is first created: at program startup time for the master thread, and when the
threads are first created for the slave threads.
When the end of a parallel region is reached, the slave threads disappear, but they do not die. Rather,
they park themselves on a queue waiting for the next parallel region. In addition, although the slave
threads are dormant, they still retain their state, in particular their instances of the thread-private common
blocks. As a result, the contents of threadprivate data persist for each thread from one parallel region to
another. When the next parallel region is reached and the slave threads are re-engaged, they can access
their threadprivate data and find the values computed at the end of the previous parallel region. This
persistence is guaranteed within OpenMP so long as the number of threads does not change. If the user
modifies the requested number of parallel threads (say, through a call to a runtime library routine), then a
new set of slave threads will be created, each with a freshly initialized set of threadprivate data.
Finally, during the serial portions of the program, only the master thread executes, and it accesses its
private copy of the threadprivate data.
4.4.2 The copyin Clause
Since each thread has its own private copy of threadprivate data for the duration of the program, there is
no way for a thread to access another thread's copy of such threadprivate data. However, OpenMP
provides a limited facility for slave threads to access the master thread's copy of threadprivate data,
through the copyin clause.
The copyin clause may be supplied along with a parallel directive. It can either provide a list of variables
from within a threadprivate common block, or it can name an entire threadprivate common block. When a
copyin clause is supplied with a parallel directive, the named threadprivate variables (or the entire
threadprivate common block if so specified) within the private copy of each slave thread are initialized
with the corresponding values in the master's copy. This propagation of values from the master to each
slave thread is done at the start of the parallel region; subsequent to this initialization, references to the
threadprivate variables proceed as before, referencing the private copy within each thread.
The copyin clause is helpful when the threadprivate variables are used for scratch storage within each
thread but still need initial values that may either be computed by the master thread, or read from an input
file into the master's copy. In such situations the copyin clause is an easy way to communicate these
values from the master's copy to that of the slave threads.
The syntax of the copyin clause is
copyin (list)
where the list is a comma-separated list of names, with each name being either a threadprivate common
block name, an individual threadprivate common block variable, or a file scope or global threadprivate
variable in C/C++. When listing the names of threadprivate common blocks, they should appear between
slashes.
We illustrate the copyin clause with a simple example. In Example 4.8 we have added another common
block called cm with an array called data, and a variable N that holds the size of this data array being
used as scratch storage. Although N would usually be a constant, in this example we are assuming that
different threads use a different-sized subset of the data array. We therefore declare the cm common
block as threadprivate. The master thread computes the value of N before the parallel region. Upon
entering the parallel region, due to the copyin clause, each thread initializes its private copy of N with the
value of N from the master thread.
Example 4.8: Using the copyin clause.
common /bounds/ istart, iend
common /cm/ N, data(1000)
!$omp threadprivate (/bounds/, /cm/)
N = ...
!$omp parallel copyin(N)