5.5. taskgroup Construct#

In this example, tasks are grouped and synchronized using the taskgroup construct.

Initially, one task (the task executing the start_background_work() call) is created in the parallel region, and later a parallel tree traversal is started (the task executing the root of the recursive compute_tree() calls). While synchronizing tasks at the end of each tree traversal, using the taskgroup construct ensures that the formerly started background task does not participate in the synchronization and is left free to execute in parallel. This is opposed to the behavior of the taskwait construct, which would include the background tasks in the synchronization.

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

/*
* name: taskgroup.1
* type: C
* version: omp_4.0
*/
extern void start_background_work(void);
extern void check_step(void);
extern void print_results(void);
struct tree_node
{
   struct tree_node *left;
   struct tree_node *right;
};
typedef struct tree_node* tree_type;
extern void init_tree(tree_type);
#define max_steps 100
void compute_something(tree_type tree)
{
   // some computation
}
void compute_tree(tree_type tree)
{
   if (tree->left)
   {
     #pragma omp task
       compute_tree(tree->left);
   }
   if (tree->right)
   {
     #pragma omp task
       compute_tree(tree->right);
   }
   #pragma omp task
   compute_something(tree);
}
int main()
{
  int i;
  tree_type tree;
  init_tree(tree);
  #pragma omp parallel
  #pragma omp single
  {
    #pragma omp task
      start_background_work();
    for (i = 0; i < max_steps; i++)
    {
        #pragma omp taskgroup
        {
           #pragma omp task
             compute_tree(tree);
        } // wait on tree traversal in this step
        check_step();
    }
  } // only now is background work required to be complete
  print_results();
  return 0;
}
!!%compiler: gfortran
!!%cflags: -fopenmp

! name: taskgroup.1
! type: F-free
! version:    omp_4.0
module tree_type_mod
  integer, parameter :: max_steps=100
  type tree_type
    type(tree_type), pointer :: left, right
  end type
  contains
    subroutine compute_something(tree)
      type(tree_type), pointer :: tree
! some computation
    end subroutine
    recursive subroutine compute_tree(tree)
      type(tree_type), pointer :: tree
      if (associated(tree%left)) then
!$omp task
        call compute_tree(tree%left)
!$omp end task
      endif
      if (associated(tree%right)) then
!$omp task
        call compute_tree(tree%right)
!$omp end task
      endif
!$omp task
      call compute_something(tree)
!$omp end task
    end subroutine
end module
program main
  use tree_type_mod
  type(tree_type), pointer :: tree
  call init_tree(tree);
!$omp parallel
!$omp single
!$omp task
  call start_background_work()
!$omp end task
  do i=1, max_steps
!$omp taskgroup
!$omp task
    call compute_tree(tree)
!$omp end task
!$omp end taskgroup ! wait on tree traversal in this step
    call check_step()
  enddo
!$omp end single
!$omp end parallel    ! only now is background work required to be complete
  call print_results()
end program