當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


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。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。