12.2. Internal Control Variables (ICVs)#

According to Section 2.3 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, nthreads-var and max-active-levels-var . The nthreads-var ICV controls the number of threads requested for encountered parallel regions; there is one copy of this ICV per task. The 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 nest-var , max-active-levels-var , dyn-var , and nthreads-var ICVs are modified through calls to the runtime library routines omp_set_nested, omp_set_max_active_levels, omp_set_dynamic, and omp_set_num_threads respectively. These ICVs affect the operation of parallel regions. Each implicit task generated by a parallel region has its own copy of the nest-var, dyn-var , and nthreads-var ICVs.

In the following example, the new value of nthreads-var applies only to the implicit tasks that execute the call to omp_set_num_threads. There is one copy of the 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 parallel region creates a team of two threads; each of the threads will execute one of the two implicit tasks generated by the outer parallel region.

Each implicit task generated by the outer parallel region calls omp_set_num_threads(3), assigning the value 3 to its respective copy of nthreads-var . Then each implicit task encounters an inner 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 parallel region.

Since the outer 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 parallel regions.

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

The print statement in the outer 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 parallel region is also executed by only one of the threads in the team. Since we have a total of two inner parallel regions, the print statement will be executed twice - once per inner parallel region.

//%compiler: clang
//%cflags: -fopenmp

/*
* name: icv.1
* type: C
*/
#include <stdio.h>
#include <omp.h>

int main (void)
{
  omp_set_nested(1);
  omp_set_max_active_levels(8);
  omp_set_dynamic(0);
  omp_set_num_threads(2);
  #pragma omp parallel
    {
      omp_set_num_threads(3);

      #pragma omp parallel
        {
          omp_set_num_threads(4);
          #pragma omp single
            {
                 // The following should print:
                 // Inner: max_act_lev=8, num_thds=3, max_thds=4
                 // Inner: max_act_lev=8, num_thds=3, max_thds=4
              printf ("Inner: max_act_lev=%d, num_thds=%d, max_thds=%d\n",
              omp_get_max_active_levels(), omp_get_num_threads(),
              omp_get_max_threads());
            }
        }

      #pragma omp barrier
      #pragma omp single
        {
                 // The following should print:
                 // Outer: max_act_lev=8, num_thds=2, max_thds=3
          printf ("Outer: max_act_lev=%d, num_thds=%d, max_thds=%d\n",
                  omp_get_max_active_levels(), omp_get_num_threads(),
                  omp_get_max_threads());
        }
    }
    return 0;
}
!!%compiler: gfortran
!!%cflags: -fopenmp

! name: icv.1
! type: F-fixed
      program icv
      use omp_lib

      call omp_set_nested(.true.)
      call omp_set_max_active_levels(8)
      call omp_set_dynamic(.false.)
      call omp_set_num_threads(2)

!$omp parallel
      call omp_set_num_threads(3)

!$omp parallel
      call omp_set_num_threads(4)
!$omp single
!      The following should print:
!      Inner: max_act_lev= 8 , num_thds= 3 , max_thds= 4
!      Inner: max_act_lev= 8 , num_thds= 3 , max_thds= 4
       print *, "Inner: max_act_lev=", omp_get_max_active_levels(),
     &           ", num_thds=", omp_get_num_threads(),
     &           ", max_thds=", omp_get_max_threads()
!$omp end single
!$omp end parallel

!$omp barrier
!$omp single
!      The following should print:
!      Outer: max_act_lev= 8 , num_thds= 2 , max_thds= 3
       print *, "Outer: max_act_lev=", omp_get_max_active_levels(),
     &           ", num_thds=", omp_get_num_threads(),
     &           ", max_thds=", omp_get_max_threads()
!$omp end single
!$omp end parallel
       end