有哪些好方法可以调整此Barrier
示例来处理两个差异:
事先不知道项目数(例如,在将大文件拆分成行的情况下)
没有跟踪线程句柄(例如,在下面的示例中没有使用handles
向量)。动机是这样做会增加额外的开销。
示例代码:
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();
}
代码段略微改编自Barrier
docs。
我想到的第一件事就是(如果可能的话)改变Barrier
的内在价值;但是,API不提供对num_threads
结构的Barrier
属性的可变访问。
另一个想法是不使用Barrier
而是使用AtomicUsize
编写自定义逻辑。
我愿意在Rust中学习最符合人体工程学/习惯用法的方法。
答案 0 :(得分:1)
您可以在atomic上使用spinlock来等待所有线程退出。当然,您可以将Arc<AtomicUsize>
传递给每个线程,而不是使用静态原子。
Ordering::SeqCst
可能过于强大,但并发编程很难,而且我不确定如何放宽这种排序。
虽然可以这样做,但创建线程的成本可能会使这种微优化相形见绌。此外,值得考虑的是,忙碌的等待会降低程序的性能。
use std::panic;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use std::thread;
use std::time::Duration;
static GLOBAL_THREAD_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
fn main() {
for i in 0..10 {
// mark that the thread is about to run
// we need to do it in the main thread to prevent spurious exits
GLOBAL_THREAD_COUNT.fetch_add(1, Ordering::SeqCst);
thread::spawn(move|| {
// We need to catch panics to reliably signal exit of a thread
let result = panic::catch_unwind(move || {
// do some work
println!("{}-th thread reporting", i+1);
});
// process errors
match result {
_ => {}
}
// signal thread exit
GLOBAL_THREAD_COUNT.fetch_sub(1, Ordering::SeqCst);
});
}
// Wait for other threads to finish.
while GLOBAL_THREAD_COUNT.load(Ordering::SeqCst) != 0 {
thread::sleep(Duration::from_millis(1));
}
}