How can I wait for an unknown number of Rust threads to complete without using tracking handles?

Viewed 5597

What are some good ways to adapt this Barrier example to handle two differences:

  1. the number of items is not known in advance (for example, in the case where splitting a large file into lines)

  2. without tracking thread handles (e.g. without using the handles vector in the example below). The motivation is that doing so adds additional overhead.

Example code:

use std::sync::{Arc, Barrier};
use std::thread;

let mut handles = Vec::with_capacity(10);
let barrier = Arc::new(Barrier::new(10));
for _ in 0..10 {
    let c = barrier.clone();
    handles.push(thread::spawn(move|| {
        // do some work
        c.wait();
    }));
}
// Wait for other threads to finish.
for handle in handles {
    handle.join().unwrap();
}

Code snippet is adapted slightly from the Barrier docs.

The first thing that crossed my mind would be (if possible) to mutate the inner value of the Barrier; however, the API does not provide mutable access to the num_threads property of the Barrier struct.

Another idea would be to not use the Barrier and instead write custom logic with AtomicUsize.

I'm open to learning the most ergonomic / idiomatic ways to do this in Rust.

2 Answers

Have each thread send its result (or just Thread::current) to a multiple-producer, single-consumer, Channel that the waiting parent thread is consuming. The standard library provides an mpsc channnel for this purpose (). It's a lot less CPU intensive than a spinlock.

Related