当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Rust Mutex用法及代码示例


本文简要介绍rust语言中 Struct std::sync::Mutex 的用法。

用法

pub struct Mutex<T: ?Sized> { /* fields omitted */ }

用于保护共享数据的互斥原语

此互斥锁将阻塞等待锁可用的线程。互斥锁也可以通过 new 构造函数静态初始化或创建。每个互斥体都有一个类型参数,表示它正在保护的数据。只能通过从 lock try_lock 返回的 RAII 守卫来访问数据,这保证了只有在互斥锁被锁定时才能访问数据。

中毒

该模块中的互斥锁实现了一种称为“poisoning” 的策略,其中只要线程在持有互斥锁时发生Panics,互斥锁就会被视为中毒。一旦互斥体中毒,所有其他线程默认无法访问数据,因为它可能被污染(某些不变量没有得到维护)。

对于互斥体,这意味着 lock try_lock 方法返回一个 Result ,指示互斥体是否已中毒。大多数互斥锁的使用将简单地 unwrap() 这些结果,在线程之间传播Panics以确保不会看到可能无效的不变量。

然而,中毒的互斥体并不能阻止对底层数据的所有访问。 PoisonError 类型有一个 into_inner 方法,该方法将返回在成功锁定时会返回的守卫。这允许访问数据,尽管锁已中毒。

例子

use std::sync::{Arc, Mutex};
use std::thread;
use std::sync::mpsc::channel;

const N: usize = 10;

// Spawn a few threads to increment a shared variable (non-atomically), and
// let the main thread know once all increments are done.
//
// Here we're using an Arc to share memory among threads, and the data inside
// the Arc is protected with a mutex.
let data = Arc::new(Mutex::new(0));

let (tx, rx) = channel();
for _ in 0..N {
    let (data, tx) = (Arc::clone(&data), tx.clone());
    thread::spawn(move || {
        // The shared state can only be accessed once the lock is held.
        // Our non-atomic increment is safe because we're the only thread
        // which can access the shared state when the lock is held.
        //
        // We unwrap() the return value to assert that we are not expecting
        // threads to ever fail while holding the lock.
        let mut data = data.lock().unwrap();
        *data += 1;
        if *data == N {
            tx.send(()).unwrap();
        }
        // the lock is unlocked here when `data` goes out of scope.
    });
}

rx.recv().unwrap();

从中毒的互斥体中恢复:

use std::sync::{Arc, Mutex};
use std::thread;

let lock = Arc::new(Mutex::new(0_u32));
let lock2 = Arc::clone(&lock);

let _ = thread::spawn(move || -> () {
    // This thread will acquire the mutex first, unwrapping the result of
    // `lock` because the lock has not been poisoned.
    let _guard = lock2.lock().unwrap();

    // This panic while holding the lock (`_guard` is in scope) will poison
    // the mutex.
    panic!();
}).join();

// The lock is poisoned by this point, but the returned result can be
// pattern matched on to return the underlying guard on both branches.
let mut guard = match lock.lock() {
    Ok(guard) => guard,
    Err(poisoned) => poisoned.into_inner(),
};

*guard += 1;

有时需要手动删除互斥锁以在封闭范围结束之前将其解锁。

use std::sync::{Arc, Mutex};
use std::thread;

const N: usize = 3;

let data_mutex = Arc::new(Mutex::new(vec![1, 2, 3, 4]));
let res_mutex = Arc::new(Mutex::new(0));

let mut threads = Vec::with_capacity(N);
(0..N).for_each(|_| {
    let data_mutex_clone = Arc::clone(&data_mutex);
    let res_mutex_clone = Arc::clone(&res_mutex);

    threads.push(thread::spawn(move || {
        let mut data = data_mutex_clone.lock().unwrap();
        // This is the result of some important and long-ish work.
        let result = data.iter().fold(0, |acc, x| acc + x * 2);
        data.push(result);
        drop(data);
        *res_mutex_clone.lock().unwrap() += result;
    }));
});

let mut data = data_mutex.lock().unwrap();
// This is the result of some important and long-ish work.
let result = data.iter().fold(0, |acc, x| acc + x * 2);
data.push(result);
// We drop the `data` explicitly because it's not necessary anymore and the
// thread still has work to do. This allow other threads to start working on
// the data immediately, without waiting for the rest of the unrelated work
// to be done here.
//
// It's even more important here than in the threads because we `.join` the
// threads after that. If we had not dropped the mutex guard, a thread could
// be waiting forever for it, causing a deadlock.
drop(data);
// Here the mutex guard is not assigned to a variable and so, even if the
// scope does not end after this line, the mutex is still released: there is
// no deadlock.
*res_mutex.lock().unwrap() += result;

threads.into_iter().for_each(|thread| {
    thread
        .join()
        .expect("The thread creating or execution failed !")
});

assert_eq!(*res_mutex.lock().unwrap(), 800);

相关用法


注:本文由纯净天空筛选整理自rust-lang.org大神的英文原创作品 Struct std::sync::Mutex。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。