%\pagebreak
\section{Internal Control Variables (ICVs)}
\label{sec:icv}
\index{internal control variables}

According to the \docref{Internal Control Variables} section of the OpenMP 4.0 specification, an OpenMP implementation must act as if there are ICVs that control 
the behavior of the program.  This example illustrates two ICVs, \plc{nthreads-var} 
and \plc{max-active-levels-var}. The \plc{nthreads-var} ICV controls the 
number of threads requested for encountered parallel regions; there is one copy 
of this ICV per task. The \plc{max-active-levels-var} ICV controls the maximum 
number of nested active parallel regions; there is one copy of this ICV for the 
whole program.

In the following example, the \plc{nest-var}, \plc{max-active-levels-var}, 
\plc{dyn-var}, and \plc{nthreads-var} ICVs are modified through calls to 
the runtime library routines \kcode{omp_set_nested}, \kcode{omp_set_max_active_levels}, \kcode{omp_set_dynamic}, and \kcode{omp_set_num_threads} respectively. These ICVs 
affect the operation of \kcode{parallel} regions. Each implicit task generated 
by a \kcode{parallel} region has its own copy of the \plc{nest-var}, \plc{dyn-var},
and \plc{nthreads-var} ICVs.

In the following example, the new value of \plc{nthreads-var} applies only to 
the implicit tasks that execute the call to \kcode{omp_set_num_threads}. There 
is one copy of the \plc{max-active-levels-var} ICV for the whole program and 
its value is the same for all tasks. This example assumes that nested parallelism 
is supported.

The outer \kcode{parallel} region creates a team of two threads; each of the threads 
will execute one of the two implicit tasks generated by the outer \kcode{parallel} 
region.

Each implicit task generated by the outer \kcode{parallel} region calls \kcode{omp_set_num_threads(\ucode{3})}, 
assigning the value 3 to its respective copy of \plc{nthreads-var}. Then each 
implicit task encounters an inner \kcode{parallel} region that creates a team 
of three threads; each of the threads will execute one of the three implicit tasks 
generated by that inner \kcode{parallel} region.

Since the outer \kcode{parallel} region is executed by 2 threads, and the inner 
by 3, there will be a total of 6 implicit tasks generated by the two inner \kcode{parallel} 
regions.

Each implicit task generated by an inner \kcode{parallel} region will execute 
the call to \kcode{omp_set_num_threads(\ucode{4})}, assigning the value 4 to its respective 
copy of \plc{nthreads-var}.

The print statement in the outer \kcode{parallel} region is executed by only one 
of the threads in the team. So it will be executed only once.

The print statement in an inner \kcode{parallel} region is also executed by only 
one of the threads in the team. Since we have a total of two inner \kcode{parallel} 
regions, the print statement will be executed twice -- once per inner \kcode{parallel} 
region.

\pagebreak
\cexample{icv}{1}

\fexample{icv}{1}

\pagebreak
\subsection{\kcode{num_threads} Clause with a List}
\label{subsec:icv_nthreads}
\index{clauses!num_threads@\kcode{num_threads}}
\index{num_threads clause@\kcode{num_threads} clause}

Prior to OpenMP 6.0, only a single argument can be specified in the 
\kcode{num_threads} clause of a \kcode{parallel} construct. 
In this case, the clause argument is used as the requested team size for 
that \kcode{parallel} region only and does not affect the value of the
\plc{nthreads-var} ICV in any generated implicit tasks for nested 
\kcode{parallel} regions.
That value is instead inherited from the value of the \plc{nthreads-var} 
ICV in the task that encountered the \kcode{parallel} construct, 
stripping away the first integer, if the value of that ICV is a list of 
multiple integers. 

In OpenMP 6.0, the \kcode{num_threads} clause permits more than one argument.
In this case, the first argument is still used as the requested team size for
the \kcode{parallel} region. The difference is the \plc{nthreads-var} ICVs of
the generated implicit tasks are set to the list of values given by the
remaining clause arguments, rather than inheriting the value of the
encountering task's \plc{nthreads-var} ICV. Consequentially, a
\kcode{num_threads} clause with an argument list may be used to control not
only the team size for a given \kcode{parallel} region, but also the 
requested team size of any nested \kcode{parallel} regions.

The following example illustrates the effect of the \kcode{num_threads} clause
for nested \kcode{parallel} regions. The program starts with the environment
variable \kcode{OMP_NUM_THREADS} set to \ucode{"4,5,6"}, which initializes the
\plc{nthreads-var} ICV of the initial task to the list \{\vcode{4,5,6}\}. Case 1 shows 
how this ICV is used to control the requested team size for a nest of three 
\kcode{parallel} regions. As indicated from the comments, with each
successive nesting level the \plc{nthreads-var} ICV inherits all but the first
integer in the \plc{nthreads-var} ICV of the task that encounters the
\kcode{parallel} construct. This pattern continues until the \plc{nthreads-var}
ICV contains only a single integer, at which point that value persists for any
further nesting levels. In Case 2, a \kcode{num_threads(\ucode{8})} clause appears on
the outermost \kcode{parallel} construct. This only has the effect of altering
the requested team size for that \kcode{parallel} region. Note that the value of
the \plc{nthreads-var} ICVs inside the \kcode{parallel} region are the same as
for Case 1. In Case 3, the \kcode{num_threads} clause is specified with
multiple arguments \kcode{(\ucode{8,2})}. This sets the \plc{nthreads-var} ICV value in each of
the generated implicit tasks to \{\vcode{2}\}, in accordance with the inheritance rules 
for the \plc{nthreads-var} ICV described above.

\cexample[6.0]{icv}{2}[2]

\ffreeexample[6.0]{icv}{2}[2]

