Структура Barrier

#![allow(unused)]
fn main() {
pub struct Barrier { /* приватные поля */ }
}

Барьер обеспечивает точку синхронизации, в которой несколько потоков будут ждать, пока все они не достигнут этой точки.

Барьеры используются для обеспечения того, что несколько потоков выполняют определенные участки кода одновременно.

Примеры

#![allow(unused)]
fn main() {
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 = Arc::clone(&barrier);
    // То же самое, что и clone: let c = barrier.clone();
    handles.push(thread::spawn(move|| {
        println!("до ожидания");
        c.wait();
        println!("после ожидания");
    }));
}

// Ждем завершения всех потоков
for handle in handles {
    handle.join().unwrap();
}
}

Методы

new

#![allow(unused)]
fn main() {
pub fn new(n: usize) -> Barrier
}

Создает новый барьер, который может блокировать заданное количество потоков.

Барьер будет блокировать вызовы wait(), пока n потоков не будут ожидать на нем. Затем все потоки будут разблокированы одновременно.

Примеры

#![allow(unused)]
fn main() {
use std::sync::Barrier;

let barrier = Barrier::new(10);
}

wait

#![allow(unused)]
fn main() {
pub fn wait(&self) -> BarrierWaitResult
}

Блокирует текущий поток до тех пор, пока все потоки не встретятся здесь.

Барьер выполняется циклически: после того как все потоки собрались вместе, они могут продолжать работу, и барьер может быть использован снова.

Возвращает BarrierWaitResult, указывающий, был ли этот поток "лидером" при прорыве барьера.

Только один поток получит BarrierWaitResult, у которого is_leader() возвращает true, когда барьер прорывается, и все остальные потоки получат результат, у которого is_leader() возвращает false.

Примеры

#![allow(unused)]
fn main() {
use std::sync::{Arc, Barrier};
use std::thread;

let mut handles = Vec::with_capacity(10);
let barrier = Arc::new(Barrier::new(10));
let leader = Arc::new(std::sync::Mutex::new(None));

for i in 0..10 {
    let c = Arc::clone(&barrier);
    let leader_ref = Arc::clone(&leader);
    handles.push(thread::spawn(move|| {
        let wait_result = c.wait();
        if wait_result.is_leader() {
            *leader_ref.lock().unwrap() = Some(i);
        }
    }));
}

// Ждем завершения всех потоков
for handle in handles {
    handle.join().unwrap();
}

// Проверяем, какой поток был лидером
let leader_id = leader.lock().unwrap().unwrap();
println!("Поток {} был лидером", leader_id);
}

Поведение

Постоянство

Барьеры можно использовать многократно и будут продолжать работать постоянно.

Потокобезопасность

Барьеры являются Sync и могут использоваться совместно между несколькими потоками.

Производительность

Реализация барьера использует мьютекс и условную переменную, что может быть не самым эффективным решением для высокопроизводительных сценариев. Для таких случаев могут существовать специализированные крейты.

Пример практического использования

Синхронизация начала вычислений:

#![allow(unused)]
fn main() {
use std::sync::{Arc, Barrier};
use std::thread;
use std::time::Instant;

let data = Arc::new(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
let barrier = Arc::new(Barrier::new(4));
let mut handles = vec![];

for i in 0..4 {
    let data = Arc::clone(&data);
    let barrier = Arc::clone(&barrier);
    
    handles.push(thread::spawn(move || {
        // Ждем, пока все потоки не будут готовы
        barrier.wait();
        
        let start = Instant::now();
        // Каждый поток обрабатывает свою часть данных
        let chunk_size = data.len() / 4;
        let start_idx = i * chunk_size;
        let end_idx = if i == 3 { data.len() } else { start_idx + chunk_size };
        
        let sum: i32 = data[start_idx..end_idx].iter().sum();
        
        (sum, start.elapsed())
    }));
}

let mut total_sum = 0;
for handle in handles {
    let (sum, duration) = handle.join().unwrap();
    total_sum += sum;
    println!("Поток вычислил сумму {} за {:?}", sum, duration);
}

println!("Общая сумма: {}", total_sum);
}

Совместимость

Барьеры доступны с Rust 1.0.0 и являются стандартным способом синхронизации потоков по точкам встречи.