Intel® C++ Compiler 16.0 User and Reference Guide

cilk_spawn

The keyword spelling is _Cilk_spawn. The header file <cilk/cilk.h> defines macros that allow an alternative spelling (in this case, cilk_spawn). This document uses the alternative spelling as defined in cilk.h.

The cilk_spawn keyword modifies a function call statement to tell the runtime system that the function may (but is not required to) run in parallel with the caller. A cilk_spawn statement can take one of the following forms:

type var =  cilk_spawn func(args); // func () returns a value

var = cilk_spawn func(args); // func () returns a value 

cilk_spawn func(args); // func () may return void

func is the name of a function which may run in parallel with the current strand. A strand is a serial sequence of instructions without any parallel control. The code following the cilk_spawn in the current routine can execute in parallel with func. func(args) may be a call to a normal (C-style) function, a member function, a lambda function, or a function object that overloads operator().

var is a variable that can be initialized or assigned from the return value of func. (It is the same type or a type convertible from the return value.) It is known as the receiver because it receives the function call result. The receiver must be omitted for void functions.

args are the arguments to the function being spawned. These arguments are evaluated before the spawn takes effect. Be careful to ensure that pass-by-reference and pass-by-address arguments have life spans that extend at least until the next cilk_sync or else the spawned function may outlive the variable and attempt to use it after it has been destroyed. This is an example of a data race.

A cilk_spawn expression must be the only expression in the right side of an assignment and cannot be part of a larger expression. For example, the following is disallowed and will cause the compiler to issue an error diagnostic:

var = var2 + cilk_spawn func(args);

A spawned function is called a child of the function that spawned it. Conversely, the function that executes the cilk_spawn statement is known as the parent of the spawned function.

A function can be spawned using any expression that is a function. For instance, you can use a function pointer or member function pointer, as in:

var = cilk_spawn (object.*pointer) (args);

You cannot spawn a function as an argument to another function:

g(cilk_spawn f()); // Not allowed

The correct approach is to spawn a function that calls both f() and g(). This is easily accomplished using a C++11 lambda:

cilk_spawn [&]{ g(f()); }();

Note that the above is different from the following:

cilk_spawn g(f());

In the latter statement, f() is executed in the parent before spawning g() whereas with the lambda, f() and g() are both executed in the child.

When spawning named lambda functions, be careful that the lifespan of the lambda extends at least until the next sync, or else the destructor for the lambda will race with the spawned call. For example:

double i = g();
if (some condition) {
   // named lambda with value capture of i
   auto f = [=i]() { double d = sin(i); f(d); };
   cilk_spawn f();
} // Ouch! destructor for f is in parallel with spawned
call.