如何在 Rust 中使用 Mutex 创建临界区?

How to create a critical section with Mutex in Rust?

我是 Rust 新手。我应该使用 MutexArcprint_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);
}