Waitgroups in OCaml

To wait for multiple threads to finish, we can use a semaphore in OCaml. Here’s an example implementation:

open Unix
open Printf

(* This is the function we'll run in every thread *)
let worker id =
  printf "Worker %d starting\n" id;
  (* Sleep to simulate an expensive task *)
  Thread.delay 1.0;
  printf "Worker %d done\n" id

(* Main function *)
let main () =
  (* Create a semaphore to synchronize threads *)
  let sem = Semaphore.create 0 in
  
  (* Launch several threads *)
  for i = 1 to 5 do
    ignore (Thread.create
      (fun () ->
        worker i;
        Semaphore.release sem)
      ())
  done;

  (* Wait for all threads to finish *)
  for _ = 1 to 5 do
    Semaphore.acquire sem
  done

(* Run the main function *)
let () = main ()

This OCaml code demonstrates the use of threads and semaphores to achieve similar functionality to the WaitGroup in the original example.

We define a worker function that simulates some work by sleeping for a second and then printing a message.

In the main function:

  1. We create a semaphore initialized to 0.
  2. We launch 5 threads, each running the worker function with a unique ID.
  3. After each thread finishes its work, it releases the semaphore.
  4. In the main thread, we acquire the semaphore 5 times, effectively waiting for all worker threads to complete.

To run this program:

$ ocamlc -thread unix.cma threads.cma semaphore.cma waitgroups.ml -o waitgroups
$ ./waitgroups
Worker 5 starting
Worker 3 starting
Worker 4 starting
Worker 1 starting
Worker 2 starting
Worker 4 done
Worker 1 done
Worker 2 done
Worker 5 done
Worker 3 done

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

Note that this approach uses OCaml’s native threads and semaphores. For more advanced use cases or better performance, you might want to consider using libraries like Lwt or Async for concurrent programming in OCaml.