cilk_spawn

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 with the type returned by func. 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 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 could 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++0x 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.

Spawning of mapped calls is supported. Spawning applies to the entire mapped call. For example, consider the following:

[:] = cilk_spawn foo(B[:]);

Calling foo with an array section argument is a mapped call, in which foo is called for each element in the array section B[:]. Spawning occurs for the entire mapped call and not each call to foo for each element.


Submit feedback on this help topic

Copyright © 1996-2011, Intel Corporation. All rights reserved.