我是Rust和线程的新手,我正在尝试打印一个数字,同时在另一个线程中添加它。我怎么能做到这一点?
use std::thread;
use std::time::Duration;
fn main() {
let mut num = 5;
thread::spawn(move || {
loop {
num += 1;
thread::sleep(Duration::from_secs(10));
}
});
output(num);
}
fn output(num: i32) {
loop {
println!("{:?}", num);
thread::sleep(Duration::from_secs(5));
}
}
上面的代码不起作用:它总是只打印5
,好像数字永远不会增加。
请阅读"Concurrency" chapter, "Safe Shared Mutable State" section of The Rust Book,它详细解释了如何做到这一点。
简而言之:
num
被复制,所以output()
和线程在数字的不同副本上运行。如果num
不可复制,Rust编译器将无法编译并出现错误。Arc
(原子引用计数变量)中Arc
中的变量,你需要把它放在Mutex
或RwLock
中。您使用.lock()
方法从Mutex
获取可变引用。该方法将确保在该可变引用的生命周期内对整个过程的独占访问。use std::thread;
use std::time::Duration;
use std::sync::{Arc, Mutex};
fn main(){
let num = Arc::new(Mutex::new(5));
// allow `num` to be shared across threads (Arc) and modified
// (Mutex) safely without a data race.
let num_clone = num.clone();
// create a cloned reference before moving `num` into the thread.
thread::spawn(move || {
loop {
*num.lock().unwrap() += 1;
// modify the number.
thread::sleep(Duration::from_secs(10));
}
});
output(num_clone);
}
fn output(num: Arc<Mutex<i32>>){
loop {
println!("{:?}", *num.lock().unwrap());
// read the number.
// - lock(): obtains a mutable reference; may fail,
// thus return a Result
// - unwrap(): ignore the error and get the real
// reference / cause panic on error.
thread::sleep(Duration::from_secs(5));
}
}
您可能还想阅读:
另一个答案解决了任何类型的问题,但作为pnkfelix Share mutable object between threads,原子包装类型是另一种解决方案,将适用于Arc<Mutex<i32>>
的特定情况。
自Rust 1.0以来,您可以使用Arc<i32>
,When would you use a Mutex without an Arc?,Arc<Mutex<i32>>
和Mutex<i32>
来同步多线程访问observes,i32
,AtomicBool
和AtomicPtr<T>
值。在Rust 1.34中,几种新的AtomicIsize
类型已经稳定,包括AtomicUsize
。 (查看bool
文档以获取当前列表。)
使用原子类型最有可能比锁定*mut T
或isize
更有效,但需要更多关注内存排序的低级细节。如果你的线程共享的数据超过了一个标准原子类型的数据,你可能需要一个usize
而不是多个Atomic
s。
也就是说,这是使用AtomicI32
而不是std::sync::atomic
的kennytm答案的一个版本:
Mutex
共享所有权仍需要RwLock
(但请参阅Mutex
)。
选择正确的记忆Atomic
远非微不足道。 AtomicI32
是最保守的选择,但如果只有一个内存地址被共享,Mutex<i32>
也应该工作。有关更多信息,请参阅以下链接。
use std::sync::{
atomic::{AtomicI32, Ordering},
Arc,
};
use std::thread;
use std::time::Duration;
fn main() {
let num = Arc::new(AtomicI32::new(5));
let num_clone = num.clone();
thread::spawn(move || loop {
num.fetch_add(1, Ordering::SeqCst);
thread::sleep(Duration::from_secs(10));
});
output(num_clone);
}
fn output(num: Arc<AtomicI32>) {
loop {
println!("{:?}", num.load(Ordering::SeqCst));
thread::sleep(Duration::from_secs(5));
}
}
Arc
(The Rustonomicon的章节)Ordering