Course contentsShow
← Rust
Lesson 1099 of 1,91010. Concurrency PrimitivesFree lesson

Barrier Synchronization Patterns

You will synchronize multiple threads at specific execution milestones to ensure collective progress.

In this lesson, you will learn how to orchestrate multiple threads to wait for one another at specific execution milestones using a Barrier.

The Core Concept

In complex parallel systems, you often need multiple threads to perform individual tasks before the entire group moves to the next phase of a computation. Imagine a simulation: if Thread A calculates physics and Thread B processes graphics, you don't want the graphics thread to render a frame based on outdated physics data. A Barrier acts as a synchronization point that forces threads to "pause and wait" until every participant has reached the same point in their execution.

Implementing with std::sync::Barrier

To use a barrier, you must initialize it with the exact number of threads that need to meet at the checkpoint. Each thread then calls .wait() when it hits that milestone.

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

let n_threads = 3;
let barrier = Arc::new(Barrier::new(n_threads));
let mut handles = Vec::with_capacity(n_threads);

for i in 0..n_threads {
    let c = Arc::clone(&barrier);
    handles.push(thread::spawn(move || {
        println!("Thread {} performing pre-work...", i);
        // The barrier forces threads to wait here
        c.wait();
        println!("Thread {} proceeding to next phase!", i);
    }));
}

for handle in handles {
    handle.join().unwrap();
}

In this example, none of the threads will print "proceeding to next phase" until all three have reached the c.wait() line. The Barrier keeps an internal counter; once it hits the pre-defined number of threads, it unblocks all of them simultaneously, allowing the computation to proceed in lockstep.

When to Use This

Barriers are highly effective for iterative algorithms—such as parallel image processing or grid-based simulations—where data dependencies exist between cycles. Without a barrier, your threads would drift apart, causing data races or logic errors as threads act on disparate versions of shared state. By enforcing these milestones, you guarantee that every thread is working with the most up-to-date data available from the previous phase.

Key Takeaway: A Barrier synchronizes the collective progress of multiple threads by forcing all participants to rendezvous at a specific line of code before any are permitted to continue.