Title here
Summary here
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:
sync bool
variable tasksDone
to signal when all tasks are complete.atomic int
variable tasksRemaining
to keep track of the number of tasks still running.begin
statement to spawn concurrent tasks.fetchSub
operation on the atomic variable is used to decrement the counter and check if it’s the last task.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.