Waitgroups in Chapel

Our example demonstrates how to wait for multiple tasks to finish using Chapel’s synchronization variables. In Chapel, we can use sync variables to achieve similar functionality to WaitGroups.

use Time;

// This is the function we'll run in every task
proc worker(id: int) {
  writeln("Worker ", id, " starting");
  
  // Sleep to simulate an expensive task
  sleep(1);
  writeln("Worker ", id, " done");
}

// This sync variable is used to wait for all the tasks launched here to finish
var tasksDone: sync bool = false;
var tasksRemaining: atomic int = 0;

// Launch several tasks
for i in 1..5 {
  tasksRemaining.add(1);
  
  // Spawn a task for each worker
  begin {
    worker(i);
    
    // Decrement the counter when the task is done
    if tasksRemaining.fetchSub(1) == 1 {
      tasksDone.writeXF(true);
    }
  }
}

// Block until all tasks are done
tasksDone.readFF();

// Note that this approach has no straightforward way to propagate errors from tasks.
// For more advanced use cases, consider using Chapel's error handling mechanisms.

To run the program:

$ chpl waitgroups.chpl
$ ./waitgroups
Worker 1 starting
Worker 2 starting
Worker 3 starting
Worker 4 starting
Worker 5 starting
Worker 1 done
Worker 2 done
Worker 3 done
Worker 4 done
Worker 5 done

The order of workers starting up and finishing is likely to be different for each invocation.

In this Chapel version:

  1. We use a sync bool variable tasksDone to signal when all tasks are complete.
  2. We use an atomic int variable tasksRemaining to keep track of the number of tasks still running.
  3. Instead of goroutines, we use Chapel’s begin statement to spawn concurrent tasks.
  4. The fetchSub operation on the atomic variable is used to decrement the counter and check if it’s the last task.
  5. We use writeXF to signal that all tasks are done, and readFF to wait for this signal.

Chapel’s concurrency model is different from Go’s, but this approach provides similar functionality to WaitGroups. The sync and atomic variables ensure proper synchronization between tasks.