9.9. depobj Construct#

The stand-alone depobj construct provides a mechanism to create a depend object that expresses a dependence to be used subsequently in the depend clause of another construct. The dependence is created from a dependence type and a storage location, within a depend clause of an depobj construct; and it is stored in the depend object. The depend object is represented by a variable of type omp_depend_t in C/C++ (by a scalar variable of integer kind omp_depend_kind in Fortran).

In the example below the stand-alone depobj construct uses the depend, update and destroy clauses to initialize , update and uninitialize a depend object (obj).

The first depobj construct initializes the obj depend object with an inout dependence type with a storage location defined by variable a. This dependence is passed into the driver routine via the obj depend object.

In the first driver routine call, Task 1 uses the dependence of the object (inout), while Task 2 uses an in dependence specified directly in a depend clause. For these task dependences Task 1 must execute and complete before Task 2 begins.

Before the second call to driver , obj is updated using the depobj construct to represent an in dependence. Hence, in the second call to driver , Task 1 will have an in dependence; and Task 1 and Task 2 can execute simultaneously. Note: in an update clause, only the dependence type can be (is) updated.

The third depobj construct uses the destroy clause. It frees resources as it puts the depend object in an uninitialized state– effectively destroying the depend object. After an object has been uninitialized it can be initialized again with a new dependence type and a new variable.

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

/*
* name:       depobj.1
* type:       C
* version:    omp_5.2
*/

#include <stdio.h>
#include <omp.h>

#define N 100
#define TRUE  1
#define FALSE 0

void driver(int update, float a[], float b[], int n, omp_depend_t *obj);

void update_copy(int update, float a[], float b[], int n);
void checkpoint(float a[],int n);
void init(float a[], int n);


int main(){

   float a[N],b[N];
   omp_depend_t obj;

   init(a, N);

   #pragma omp depobj(obj) depend(inout: a)

   driver(TRUE,  a,b,N, &obj);  // updating a occurs

   #pragma omp depobj(obj) update(in)

   driver(FALSE, a,b,N, &obj);  // no updating of a

   #pragma omp depobj(obj) destroy(obj)  // obj is set to uninitialized
                                         // state, resources are freed
   return 0;

}

void driver(int update, float a[], float b[], int n, omp_depend_t *obj)
{
   #pragma omp parallel num_threads(2)
   #pragma omp single
   {

      #pragma omp task depend(depobj: *obj) // Task 1, uses depend object
         update_copy(update, a,b,n); // may update a, always copy a to b

     #pragma omp task depend(in: a[:n])     // Task 2, only read a
         checkpoint(a,n);
   }
}

void update_copy(int update, float a[], float b[], int n)
{
   if(update) for(int i=0;i<n;i++) a[i]+=1.0f;

   for(int i=0;i<n;i++) b[i]=a[i];
}

void checkpoint(float a[], int n)
{
   for(int i=0;i<n;i++) printf(" %f ",a[i]);
   printf("\n");
}

void init(float a[], int n)
{
   for(int i=0;i<n;i++) a[i]=i;
}
!!%compiler: gfortran
!!%cflags: -fopenmp

! name:       depobj.1
! type:       F-free
! version: omp_5.2

program main
    use omp_lib
    implicit none

    integer,parameter        :: N=100
    real                     :: a(N),b(N)
    integer(omp_depend_kind) :: obj

    call init(a, N)

    !$omp depobj(obj) depend(inout: a)

    call driver(.true.,  a,b,N, obj)  !! updating occurs

    !$omp depobj(obj) update(in)

    call driver(.false., a,b,N, obj)  !! no updating

    !$omp depobj(obj) destroy(obj)    !! obj is set to uninitialized
                                      !! state, resources are freed

end program

subroutine driver(update, a, b, n, obj)
   use omp_lib
   implicit none
   logical :: update
   real    :: a(n), b(n)
   integer :: n
   integer(omp_depend_kind) :: obj

   !$omp parallel num_threads(2)

     !$omp single

       !$omp task depend(depobj: obj)       !! Task 1, uses depend object
         call update_copy(update, a,b,n)
              !! update a or not, always copy a to b
       !$omp end task

       !$omp task depend(in: a)             !! Task 2, only read a
         call checkpoint(a,n)
       !$omp end task

     !$omp end single

   !$omp end parallel

end subroutine

subroutine update_copy(update, a, b, n)
   implicit none
   logical :: update
   real    :: a(n), b(n)
   integer :: n

   if (update) a = a + 1.0

   b = a

end subroutine

subroutine checkpoint( a, n)
   implicit none
   integer :: n
   real    :: a(n)
   integer :: i

   write(*,'( *(f5.0) )') (a(i), i=1,n)
end subroutine

subroutine init(a,n)
   implicit none
   integer :: n
   real    :: a(n)
   integer :: i

   a=[ (i, i=1,n) ]
end subroutine