首页 > 解决方案 > 如何在 Rust 中使用 Mutex 创建临界区?

问题描述

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

标签: rustsynchronizationthread-safetymutex

解决方案


MutexRust 中的锁的工作方式可能与您可能习惯的其他语言中的锁工作方式不同。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实际上在内部使用锁的锁,并提供类似的 API Mutex

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 
}

在您的简化示例中,在每个线程中创建一个长寿命锁会适得其反,因为每个线程都会阻塞其他线程,结果是顺序的而不是并发的。如果您的实际代码有更多工作要做,这可能仍然有意义。


推荐阅读