depobj Construct
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