next up previous
Next: Polygon Overlay in ICC++ Up: ICC++: A C++ Dialect Previous: ArraysObjects, and Collections

Unstructured Concurrency

  Concurrent blocks and loops provide a structured mechanism for expressing concurrency using traditional C++ control structures. However, a less-structured mechanism is sometimes required to express complex concurrency. ICC++ provides spawn and reply to support this unstructured concurrency. The spawn statement generates parallelism, while the reply object gives the user precise control of caller/callee synchronization.

Spawn

  The statement:
spawn s;
creates a new thread to execute the statement s, which can be an arbitrary statement, including a compound one. All local variables in scope at the spawn statement become read-only constants in the spawned thread. This prevents unsynchronized access to them by the spawning and spawned threads.

The spawned and spawning threads are guaranteed to run concurrently. This contrasts with conc, which is an annotation This guarantee provides the programmer with more direct control over concurrency but can be expensive to enforce, and should be used only when absolutely vital. In this context, ``concurrently'' means only that neither must wait for the other. The execution of spawner and spawnee will be interleaved if that is required. This is formally known as weak fairness.

Reply

  The reply object may be used to differentiate a function that is returning a value and a function that is exiting. Conceptually, every function has a logical object called reply, which accepts operator ()( τ ), where τ is the function's return type. The reply object is of the ICC++ builtin type reply_t. Calling reply returns a value to the function's caller without terminating the function, allowing caller and callee to continue concurrently.

void main(void) {
 Worker worker;

 int total = compute_total(worker);
}

int compute_total(Worker &worker) {
 reply(worker.total());
 worker.clear_caches();
}

In the above example, compute_total is ready to return an answer before it has finished executing; using the reply idiom allows compute_total and main to continue concurrently.

Unstructured Idioms

  spawn and reply can be used to implement customized communication and synchronization structures. For example, tail forwarding [21] can accomplished with spawn reply(e).

int factorial(int i) {
  if (i < 1)
    return 1;
  else
    spawn reply(i*factorial(i-1));
}

The expression e will be spawned and the spawned thread will return he result to the caller of the spawning function. The reply object can also be passed out of a function, effectively delegating the job of returning a value to some other function. This can be used to create synchronization structures, such as the barrier shown below.

class Barrier {
  int limit;
  int count;
  reply_t replies[];

 public:
  Barrier(int ilimit) {
    count = 0;
    limit = ilimit;
    replies = new reply_t[ilimit];
  }

  void wait(void) {
    replies[count++] = reply;
    if (count == limit) 
      for(int i = 0; i < limit; i++)
        replies[i]();
  }
};

With the Barrier given above, functions can synchronize by all calling wait, where the reply objects are stored into an array. When they have all arrived, the barrier will return values to all of them simultaneously.

Barrier b(10);

void Worker::work(void) {
  // computation here
  b.wait();

  // communication here
  b.wait();
};

next up previous
Next: Polygon Overlay in ICC++ Up: ICC++: A C++ Dialect Previous: ArraysObjects, and Collections

Julian Dolby
dolby@cs.uiuc.edu