Struct std::sync::Mutex1.0.0[][src]

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

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

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

Poisoning

此模块中的互斥锁实现了一种称为 “poisoning” 的策略,只要线程 panics 按住互斥锁,互斥锁就会被视为中毒。 一旦互斥锁中毒,默认情况下,所有其他线程都无法访问数据,因为它很可能已被污染 (某些不变性未得到维护)。

对于互斥锁,这意味着 locktry_lock 方法返回一个 Result,该 Result 指示互斥锁是否已中毒。 互斥锁的大多数用法将只是 unwrap() 这些结果,从而在线程之间传播 panics 以确保不会看到可能无效的不变式。

但是,中毒的互斥锁不会阻止对底层数据的所有访问。 PoisonError 类型具有 into_inner 方法,该方法将返回保护,否则将在成功锁定后返回该保护。 尽管锁被中毒,这仍允许访问数据。

Examples

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

const N: usize = 10;

// Spawn 几个线程用于递增共享变量 (non-atomically),并在完成所有递增操作后让主线程知道。
// 在这里,我们使用 Arc 在线程之间共享内存,并且 Arc 中的数据受到互斥锁的保护。
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 || {
        // 只有持有锁后,才能访问共享状态。
        // 我们的非原子增量是安全的,因为当持有锁时,我们是唯一可以访问共享状态的线程。
        // 我们用 unwrap() 的返回值来断言,我们不希望线程在持有锁的同时失败。
        let mut data = data.lock().unwrap();
        *data += 1;
        if *data == N {
            tx.send(()).unwrap();
        }
        // `data` 离开作用域时,此处的锁已解锁。
    });
}

rx.recv().unwrap();
Run

要从中毒的互斥锁中恢复:

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 || -> () {
    // 该线程将首先获取互斥锁,因为该锁尚未中毒,所以将解开 `lock` 的结果。
    let _guard = lock2.lock().unwrap();

    // 按住锁 (`_guard` 在作用域中) 时,此 panic 将中毒互斥锁。
    panic!();
}).join();

// 到此为止,锁定都会中毒,但是可以对返回的结果进行模式匹配,以返回两个分支上的基础防护。
let mut guard = match lock.lock() {
    Ok(guard) => guard,
    Err(poisoned) => poisoned.into_inner(),
};

*guard += 1;
Run

时需要手动丢弃互斥锁守卫,以便在封闭作用域结束之前将其解锁。

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();
        // 这是一些重要而长期的工作的结果。
        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();
// 这是一些重要而长期的工作的结果。
let result = data.iter().fold(0, |acc, x| acc + x * 2);
data.push(result);
// 我们明确丢弃 `data`,因为不再需要 `data`,并且线程仍然有工作要做。
// 这允许其他线程立即开始处理数据,而无需等待其余无关工作在这里完成。
// 它在这里比在线程中更重要,因为在此之后我们对线程进行 `.join` 处理。
// 如果我们没有丢弃互斥锁守卫,则线程可能会永远等待它,从而导致死锁。
drop(data);
// 这里互斥锁防护未分配给变量,因此,即使作用域在此行之后没有结束,互斥锁仍被释放: 没有死锁。
*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);
Run

Implementations

在解锁状态下创建一个新的互斥锁,以备使用。

Examples

use std::sync::Mutex;

let mutex = Mutex::new(0);
Run

获取一个互斥锁,阻塞当前线程,直到能够这样做为止。

该函数将阻塞本地线程,直到可用于获取互斥锁为止。 返回时,该线程是唯一持有锁的线程。 返回了 RAII 守卫,以允许对锁进行一定范围的解锁。 当守卫离开作用域时,互斥锁将被解锁。

未指定将互斥锁锁定在已经持有该锁的线程中的确切行为。 但是,该函数不会在第二次调用时返回 (例如,可能为 panic 或死锁)。

Errors

如果互斥锁的另一个用户在握住互斥锁时恐慌,则一旦获取互斥锁,此调用将返回错误。

Panics

如果当前线程已锁定,则调用此函数时可能为 panic。

Examples

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

let mutex = Arc::new(Mutex::new(0));
let c_mutex = Arc::clone(&mutex);

thread::spawn(move || {
    *c_mutex.lock().unwrap() = 10;
}).join().expect("thread::spawn failed");
assert_eq!(*mutex.lock().unwrap(), 10);
Run

尝试获取此锁。

如果此时无法获取锁,则返回 Err。 否则,将返回 RAII 守卫。当守卫被丢弃时,锁将被解锁。

该函数不会阻止。

Errors

如果该调用的另一个用户同时持有互斥锁,则该调用将返回 Poisoned 错误,否则将获得该调用的拒绝互锁。

如果互斥锁已被锁定而无法获取,则该调用将返回 WouldBlock 错误。

Examples

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

let mutex = Arc::new(Mutex::new(0));
let c_mutex = Arc::clone(&mutex);

thread::spawn(move || {
    let mut lock = c_mutex.try_lock();
    if let Ok(ref mut mutex) = lock {
        **mutex = 10;
    } else {
        println!("try_lock failed");
    }
}).join().expect("thread::spawn failed");
assert_eq!(*mutex.lock().unwrap(), 10);
Run
🔬 This is a nightly-only experimental API. (mutex_unlock #81872)

立即丢弃这个守卫,从而解锁互斥锁。

此函数等效于在守卫上调用 drop,但更具自记录性。 或者,守卫离开作用域时将自动丢弃。

#![feature(mutex_unlock)]

use std::sync::Mutex;
let mutex = Mutex::new(0);

let mut guard = mutex.lock().unwrap();
*guard += 20;
Mutex::unlock(guard);
Run

确定互斥锁是否中毒。

如果另一个线程处于活动状态,则互斥锁仍可随时中毒。 如果没有其他同步,则不应信任 false 值来确保程序正确性。

Examples

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

let mutex = Arc::new(Mutex::new(0));
let c_mutex = Arc::clone(&mutex);

let _ = thread::spawn(move || {
    let _lock = c_mutex.lock().unwrap();
    panic!(); // 互斥锁中毒
}).join();
assert_eq!(mutex.is_poisoned(), true);
Run

使用此互斥锁,返回基础数据。

Errors

如果此互斥锁的另一个用户在按住互斥锁时恐慌,则此调用将返回错误。

Examples

use std::sync::Mutex;

let mutex = Mutex::new(0);
assert_eq!(mutex.into_inner().unwrap(), 0);
Run

返回对基础数据的可变引用。

由于此调用借用 Mutex 是可变的,因此不需要进行实际的锁定 - 可变借用可以静态地保证不存在任何锁定。

Errors

如果此互斥锁的另一个用户在按住互斥锁时恐慌,则此调用将返回错误。

Examples

use std::sync::Mutex;

let mut mutex = Mutex::new(0);
*mutex.get_mut().unwrap() = 10;
assert_eq!(*mutex.lock().unwrap(), 10);
Run

Trait Implementations

使用给定的格式化程序格式化该值。 Read more

创建一个 Mutex<T>,其 T 值为 Default

在解锁状态下创建一个新的互斥锁,以备使用。 这等效于 Mutex::new

Auto Trait Implementations

Blanket Implementations

获取 selfTypeIdRead more

从拥有的值中一成不变地借用。 Read more

从拥有的值中借用。 Read more

执行转换。

执行转换。

执行转换。

发生转换错误时返回的类型。

执行转换。

发生转换错误时返回的类型。

执行转换。