Rust 併發控制之 Barrier

Rust 有很多種控制併發的方式,Barrier(屏障)是其中一種用來同步多線程計算的方式。

今天拿代碼來簡單看下。

比如我們要多線程計算,期望所有線程都計算完畢再輸出最終結果。常規多線程代碼示例可以用線程 join 來等待

use std::sync::{Arc, Mutex};

fn main() {
    let numthreads = 10;
    let my_mutex = Arc::new(Mutex::new(0));
    let mut handlers = Vec::with_capacity(numthreads);

    for _ in 0..numthreads {
        let my_lock = my_mutex.clone();
        handlers.push(std::thread::spawn(move || {
            let mut guard = my_lock.lock().unwrap();
            *guard += 1;
        }));
    }
    for handler in handlers {
        handler.join().unwrap();
    }

    let answer = { *my_mutex.lock().unwrap() };
    assert_eq!(answer, numthreads);
}

而如果用 Barrier,我們可以這麼寫:

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

fn main() {
    let numthreads = 10;
    let my_mutex = Arc::new(Mutex::new(0));

    // We use a barrier to ensure the readout happens after all writing
    let barrier = Arc::new(Barrier::new(numthreads + 1));

    for i in 0..numthreads {
        let my_barrier = barrier.clone();
        let my_lock = my_mutex.clone();
        std::thread::spawn(move || {
            let mut guard = my_lock.lock().unwrap();
            *guard += 1;

            // Release the lock to prevent a deadlock
            drop(guard);
            println!("thread {} is ready", i);
            // Blocks the current thread until all threads have rendezvoused here.
            my_barrier.wait();
            println!("thread {} is done", i)
        });
    }

    // A barrier will block `n`-1 threads which call [`wait()`] and then wake
    // up all threads at once when the `n`th thread calls [`wait()`].
    barrier.wait();

    let answer = { *my_mutex.lock().unwrap() };
    assert_eq!(answer, numthreads);
}

Barrier 可以用 wait 來控制 n 個線程的同步,數量需要提前指明。當調用 wait 時,如果不是第 n 個,就會一直阻塞當前線程,直到第 n 個 wait 調用,才能進行後續操作。

這種機制就像在多個線程中插入了一道屏障,當所有線程都執行到這裏時,才能解除屏障繼續向後執行。

當然這樣實現相較於第一種,在線程數量大的時候也是會有比較明顯的性能開銷的,底層是使用 condvar+mutex 來實現的。這種組合也是一種有意思的併發控制方式,下次我們再聊聊它們。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/X4hIhzggiv-nv4vAxvX6Rw