在this博客文章中,作者表明 Rust 不允许通过引用捕获变量:
use std::thread;
use std::sync::atomic::{AtomicI32, Ordering};
struct ThreadSafeCounter {
count: AtomicI32,
}
impl ThreadSafeCounter {
fn increment(&mut self) { self.count.fetch_add(1, Ordering::SeqCst); }
}
pub fn main() {
let n = 10;
let mut counter = ThreadSafeCounter { count: AtomicI32::new(0) };
let mut threads = Vec::new();
for _ in 0..n {
threads.push(thread::spawn( || {
// Rust won't allow this. We are attempting to mutably borrow
// the same value multiple times.
counter.increment();
}));
}
for thread in threads { thread.join(); }
println!("{}", counter.count.load(Ordering::SeqCst));
}
然后对代码进行一项更改,并表示:
Rust 对线程安全的回答是允许对不可变对象进行突变 参考。 Rust 称之为“内部可变性”。带着一个小 更改后,前面的示例将按预期编译并工作:
use std::thread;
use std::sync::atomic::{AtomicI32, Ordering};
struct ThreadSafeCounter {
count: AtomicI32,
}
impl ThreadSafeCounter {
// increment() uses "interior mutability": it accepts an immutable
// reference, but ultimately mutates the value.
fn increment(&self) { self.count.fetch_add(1, Ordering::SeqCst); }
}
pub fn main() {
let n = 10;
let mut counter = ThreadSafeCounter { count: AtomicI32::new(0) };
let mut threads = Vec::new();
for _ in 0..n {
threads.push(thread::spawn( || {
counter.increment();
}));
}
for thread in threads { thread.join(); }
println!("{}", counter.count.load(Ordering::SeqCst));
}
我得到的错误是:
强制关闭取得
(以及任何其他 引用的变量),使用counter
关键字:move
这应该可以编译吗?该帖子写于 2021 年 12 月 18 日。
博客文章不正确。该代码无法在任何 Rust 版本(2015、2018 或 2021)下编译,原因有两个:
counter
存在于main
的堆栈中,因此它最终会超出范围。生成的线程只要正在执行就需要访问。move
放入第一个生成的线程中解决了生命周期问题,counter
将不可用于后续生成的线程。
counter
一个新的
move
计数器引用到每个生成的线程中:Arc