如何在 Rust 中使用 Mutex 创建临界区?
How to create a critical section with Mutex in Rust?
我是 Rust 新手。我应该使用 Mutex
和 Arc
在 print_lots
函数中创建一个关键部分来阻止竞争条件的发生。有什么想法吗?
fn main() {
let num_of_threads = 4;
let mut array_of_threads = vec![];
for id in 0..num_of_threads {
array_of_threads.push(std::thread::spawn(move || print_lots(id)));
}
for t in array_of_threads {
t.join().expect("Thread join failure");
}
}
fn print_lots(id: u32) {
println!("Begin [{}]", id);
for _i in 0..100 {
print!("{} ", id);
}
println!("\nEnd [{}]", id);
}
Rust 中的 Mutex
可能与锁在您可能习惯的其他一些语言中的工作方式不同。 Rust Mutex
拥有数据并防止在没有首先获得锁的情况下访问它,而不是独立于值跟踪锁,这是在编译时强制执行的。
您收到的警告是因为您已锁定 Mutex
,但随后未对该值进行任何操作。出现警告是因为这几乎肯定是一个错误。
fn main() {
let foo = Mutex::new(0);
// It's often best to just unwrap and panic if the lock is poisoned
if let Ok(mut lock) = foo.lock() {
*lock = 2;
// The mutex is unlocked automatically when lock goes out of scope here
}
println!("{:?}", foo); // Mutex { data: 2 }
}
我猜你真正的问题是你想同步打印语句,这样不同线程的输出就不会混合在一起。
一种方法是获取 StdOut
上的锁,它实际上在内部使用锁并提供与 Mutex
类似的 API:
fn print_lots(id: u32) {
let stdout = io::stdout();
println!("Begin [{}]", id);
let mut handle = stdout.lock();
for _i in 0..100 {
write!(&mut handle, "{} ", id).unwrap();
}
println!("\nEnd [{}]", id);
// handle is dropped here, unlocking stdout
}
在您的简化示例中,在每个线程中创建一个长期锁会适得其反,因为每个线程都会阻塞其他线程,结果是顺序的而不是并发的。如果您的实际代码还有更多内容,这可能仍然有意义。
use std::sync::{Arc, Mutex};
fn main() {
let num_of_threads = 4;
let mut array_of_threads = vec![];
let counter = Arc::new(Mutex::new(0));
for id in 0..num_of_threads {
let counter_clone = counter.clone();
array_of_threads.push(std::thread::spawn(move || print_lots(id, counter_clone)));
}
for t in array_of_threads {
t.join().expect("Thread join failure");
}
}
fn print_lots(id: u32, c: Arc<Mutex<u32>>) {
println!("Begin [{}]", id);
let _guard = c.lock().unwrap();
for _i in 0..100 {
print!("{} ", id);
}
println!("\nEnd [{}]", id);
}
我是 Rust 新手。我应该使用 Mutex
和 Arc
在 print_lots
函数中创建一个关键部分来阻止竞争条件的发生。有什么想法吗?
fn main() {
let num_of_threads = 4;
let mut array_of_threads = vec![];
for id in 0..num_of_threads {
array_of_threads.push(std::thread::spawn(move || print_lots(id)));
}
for t in array_of_threads {
t.join().expect("Thread join failure");
}
}
fn print_lots(id: u32) {
println!("Begin [{}]", id);
for _i in 0..100 {
print!("{} ", id);
}
println!("\nEnd [{}]", id);
}
Mutex
可能与锁在您可能习惯的其他一些语言中的工作方式不同。 Rust Mutex
拥有数据并防止在没有首先获得锁的情况下访问它,而不是独立于值跟踪锁,这是在编译时强制执行的。
您收到的警告是因为您已锁定 Mutex
,但随后未对该值进行任何操作。出现警告是因为这几乎肯定是一个错误。
fn main() {
let foo = Mutex::new(0);
// It's often best to just unwrap and panic if the lock is poisoned
if let Ok(mut lock) = foo.lock() {
*lock = 2;
// The mutex is unlocked automatically when lock goes out of scope here
}
println!("{:?}", foo); // Mutex { data: 2 }
}
我猜你真正的问题是你想同步打印语句,这样不同线程的输出就不会混合在一起。
一种方法是获取 StdOut
上的锁,它实际上在内部使用锁并提供与 Mutex
类似的 API:
fn print_lots(id: u32) {
let stdout = io::stdout();
println!("Begin [{}]", id);
let mut handle = stdout.lock();
for _i in 0..100 {
write!(&mut handle, "{} ", id).unwrap();
}
println!("\nEnd [{}]", id);
// handle is dropped here, unlocking stdout
}
在您的简化示例中,在每个线程中创建一个长期锁会适得其反,因为每个线程都会阻塞其他线程,结果是顺序的而不是并发的。如果您的实际代码还有更多内容,这可能仍然有意义。
use std::sync::{Arc, Mutex};
fn main() {
let num_of_threads = 4;
let mut array_of_threads = vec![];
let counter = Arc::new(Mutex::new(0));
for id in 0..num_of_threads {
let counter_clone = counter.clone();
array_of_threads.push(std::thread::spawn(move || print_lots(id, counter_clone)));
}
for t in array_of_threads {
t.join().expect("Thread join failure");
}
}
fn print_lots(id: u32, c: Arc<Mutex<u32>>) {
println!("Begin [{}]", id);
let _guard = c.lock().unwrap();
for _i in 0..100 {
print!("{} ", id);
}
println!("\nEnd [{}]", id);
}