Intel® C++ Compiler 16.0 User and Reference Guide

omp task

Specifies the beginning of a code block whose execution may be deferred.

Syntax

#pragma omp task [clause[[,]clause]...]

block

Arguments

clause

Can be any of the following:

final(scalar_expression)

When the scalar_expression evaluates to true, it specifies that the generated task will be a final task.

Note

final task is a task that forces all of its descendant tasks to become included tasks.

All task constructs encountered during execution of a final task will generate included tasks.

If a variable is used in a final clause expression of a task construct, it causes an implicit reference to the variable in all enclosing constructs.

Only a single final clause can appear in the task pragma.

private(list)

Declares variables to be private to each thread in a team.

firstprivate(list)

Provides a superset of the functionality provided by the private clause. Each private data object is initialized with the value of the original object.

shared(list)

Shares variables in list among all the threads in a team.

default(shared|none)

default(shared) specifies that the variables used in a task, but not explicitly declared in a private, firstprivate or shared clause will be made shared. default(none) specifies that the variables used in a task, but not explicitly declared in a private, firstprivate, or shared clause will be flagged with a syntax error at compile time.

depend

The dependence-type can be one or more of the following, the list items can be variables and array sections:

  • in(list): the generated task will be a dependent task of all previously generated sibling tasks that reference at least one of the list items in an out or inout clause.

  • out(list): the generated task will be a dependent task of all previously generated sibling tasks that reference at least one of the list items in an in, out, or inout clause.

  • inout(list): the generated task will be a dependent task of all previously generated sibling tasks that reference at least one of the list items in an in, out, or inout clause.

untied

Specifies that the task is never tied to the thread that started its execution. Any thread in the team can resume the task region after a suspension. For example, during runtime, the compiler can start the execution of a given task on thread A, break execution, and later resume it on thread B.

if(scalar_expression)

Specifies that the enclosed code section is to be executed in parallel only if the scalar_expression evaluates to true. If this clause is not used, the region is executed as if an if(true) clause was specified.

If the scalar_expression evaluates to false, the encountering thread must suspend the current task region and begin execution of the generated task immediately. The suspended task region will not be resumed until the generated task is completed.

This clause is evaluated by the master thread before any data scope attributes take effect.

Only a single if clause may appear in the task pragma.

mergeable

When the generated task is an undeferred task or an included task, it specifies that the implementation may generate a merged task instead.

Note

An undeferred task is a task for which execution is not deferred with respect to its generating task region, that is, its generating task region is suspended until execution of the undeferred task is completed.

An included task is a task for which execution is sequentially included in the generating task region, that is, it is undeferred and executed immediately by the encountering thread.

A merged task is a task whose data environment, inclusive of internal control variables, is the same as that of its generating task region. Internal control variables (ICVs) are discussed in the latest OpenMP* specifications.

block

Is a structured block of statements or constructs. You cannot branch into or out of the block.

Description

When a thread encounters a task construct, a task is generated from the code for the associated structured block. The encountering thread may immediately execute the task, or defer its execution. In the latter case, any thread in the team may be assigned the task.

A thread that encounters a task scheduling point within the task region may temporarily suspend the task region. By default, a task is then tied and its suspended task region can only be resumed by the thread that started its execution. However, if the untied clause is specified in a task construct, any thread in the team can resume the task region after a suspension. The untied clause is ignored in the following cases:

A task construct may be nested inside an outer task, but the task region of the inner task is not a part of the task region of the outer task.

The task construct includes a task scheduling point in the task region of its generating task, immediately following the generation of the explicit task. Each explicit task region includes a task scheduling point at its point of completion. An implementation may add task scheduling points anywhere in untied task regions.

Note that when storage is shared by an explicit task region, you must add proper synchronization to ensure that the storage does not reach the end of its lifetime before the explicit task region completes its execution.

A program must not depend on any ordering of the evaluations of the clauses of the task pragma and it must not depend on any side effects of the evaluations of the clauses. A program that branches into or out of a task region is non-conforming.

Unsynchronized use of C++ I/O statements by multiple tasks on the same unit has unspecified behavior.

Example

struct node {
  struct node *left;
  struct node *right;
};

extern void process(struct node *);
int depth, limit;

void traverse( struct node *p ) {
  // When depth>limit, stop generating new tasks, and allow the 
  // compiler to avoid creating a new data environment.

  if (p->left)
  #pragma omp task final(depth>limit) mergeable
    // p is firstprivate by default
traverse(p->left);
if (p->right)
#pragma omp task final(depth>limit) mergeable
     // p is firstprivate by default
traverse(p->right);
process(p);
}

Example: Creating Tasks with Dependencies

int a;
  #pragma omp task depend(out:a) {}
  #pragma omp task depend(in:a) {}
  #pragma omp task depend(in:a) {}
  #pragma omp task depend(out:a) {}

Above is a simple example where a four tasks with dependencies are created. The first task does not depend on any previous one. The second and third tasks depend on the first one, but not on each other. The last task depends on the second and third.

Example: Sibling Tasks with Dependencies

 int a[N*B];
  for (int I=0; I< N; I++ )  
    #pragma omp task depend(output:a[i*B:B])
      Fill(&a[i*B]);

  for (int I = 0; I <–1; I++ )
    #pragma omp task depend(inout:a[i*B:B]) depend(in:a[(i+1)*B:B])
      Process(&a[i*B],&a[(I+1)*B]);

  for (int I = 0; I <N; I++ )
    #pragma omp task depend(in:a[i*B:B])
       Output(&a[i*B]);

The tasks of the first loop will be independent of any other, as there is no previous tasks that express a dependence on the same list items. Task on the second loop will depend on two tasks from the first loop (the one that references I*B and that references (I+1)*B).

Because dependencies are constructed in a sequential order the in dependencies forces the tasks of the loop to be dependent on the task from the previous iteration to be processed. Finally, tasks from the third loop can be executed when the corresponding Process task from the second loop is executed.