Struct std::sync::Mutex

1.0.0 · source ·
pub struct Mutex<T: ?Sized> { /* private fields */ }
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;

// 产生几个线程来增加一个共享变量 (非原子的),并在完成所有递增操作后,就让主线程知道。
// 在这里,我们使用 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();

    // 持有锁时的这种 panic (`_guard` 在作用域内) 将使互斥锁中毒。
    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 || {
        // 这里我们用一个 block 来限制锁卫的生命周期。
        let result = {
            let mut data = data_mutex_clone.lock().unwrap();
            // 这是一些重要而长期的工作的结果。
            let result = data.iter().fold(0, |acc, x| acc + x * 2);
            data.push(result);
            result
            // 交互锁守卫在这里得到抛弃,连同在关键部分创建的任何其他值。
        };
        // 这里创建的守卫是语句末尾的临时丢弃,即
        // 即使线程做了一些额外的工作,锁也不会保持持有状态。
        *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` 函数。
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§

source§

impl<T> Mutex<T>

const: 1.63.0 · source

pub const fn new(t: T) -> Mutex<T>

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

Examples
use std::sync::Mutex;

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

impl<T: ?Sized> Mutex<T>

source

pub fn lock(&self) -> LockResult<MutexGuard<'_, T>>

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

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

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

Errors

如果互斥锁的另一个用户在持有互斥锁时 panic,那么一旦获取了互斥锁,这个调用将返回一个错误。

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
source

pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>>

尝试获取此锁。

如果此时无法获取锁,则返回 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
source

pub fn unlock(guard: MutexGuard<'_, T>)

🔬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
1.2.0 · source

pub fn is_poisoned(&self) -> bool

确定互斥锁是否中毒。

如果另一个线程处于活动状态,则互斥锁仍可随时中毒。 如果没有其他同步,则不应信任 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
source

pub fn clear_poison(&self)

🔬This is a nightly-only experimental API. (mutex_unpoison #96469)

从互斥锁中清除中毒状态

如果互斥锁中毒了,它将保持中毒状态,直到调用这个函数为止。 这允许从中毒状态中恢复并标记它已经恢复。 例如,如果该值被已知良好的值覆盖,则互斥锁可以被标记为未中毒。 或者可能,可以检查该值,以确定它是否处于一致状态,如果是,则会清除中毒状态。

Examples
#![feature(mutex_unpoison)]

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);
let x = mutex.lock().unwrap_or_else(|mut e| {
    **e.get_mut() = 1;
    mutex.clear_poison();
    e.into_inner()
});
assert_eq!(mutex.is_poisoned(), false);
assert_eq!(*x, 1);
Run
1.6.0 · source

pub fn into_inner(self) -> LockResult<T>where T: Sized,

消耗此互斥锁,返回底层数据。

Errors

如果此互斥锁的另一个用户在持有互斥锁时 panic,则此调用将返回错误。

Examples
use std::sync::Mutex;

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

pub fn get_mut(&mut self) -> LockResult<&mut T>

返回对底层数据的可变引用。

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

Errors

如果此互斥锁的另一个用户在持有互斥锁时 panic,则此调用将返回错误。

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§

source§

impl<T: ?Sized + Debug> Debug for Mutex<T>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

使用给定的格式化程序格式化该值。 Read more
1.10.0 · source§

impl<T: ?Sized + Default> Default for Mutex<T>

source§

fn default() -> Mutex<T>

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

1.24.0 · source§

impl<T> From<T> for Mutex<T>

source§

fn from(t: T) -> Self

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

1.12.0 · source§

impl<T: ?Sized> RefUnwindSafe for Mutex<T>

source§

impl<T: ?Sized + Send> Send for Mutex<T>

source§

impl<T: ?Sized + Send> Sync for Mutex<T>

1.9.0 · source§

impl<T: ?Sized> UnwindSafe for Mutex<T>

Auto Trait Implementations§

§

impl<T: ?Sized> Unpin for Mutex<T>where T: Unpin,

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

获取 selfTypeIdRead more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

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

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

从拥有的值中借用。 Read more
source§

impl<T> From<!> for T

source§

fn from(t: !) -> T

从输入类型转换为此类型。
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

返回未更改的参数。

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

调用 U::from(self)

也就是说,这种转换是 From<T> for U 实现选择执行的任何操作。

source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

执行转换。
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

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

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

执行转换。