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