本文簡要介紹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 Mutex.new用法及代碼示例
- Rust Mutex.get_mut用法及代碼示例
- Rust Mutex.lock用法及代碼示例
- Rust Mutex.into_inner用法及代碼示例
- Rust Mutex.is_poisoned用法及代碼示例
- Rust Mutex.unlock用法及代碼示例
- Rust Mutex.try_lock用法及代碼示例
- Rust MulAssign.mul_assign用法及代碼示例
- Rust MulAssign用法及代碼示例
- Rust Mul用法及代碼示例
- Rust Mul.mul用法及代碼示例
- Rust MaybeUninit.assume_init_mut用法及代碼示例
- Rust MetadataExt.st_ctime_nsec用法及代碼示例
- Rust MetadataExt.mtime_nsec用法及代碼示例
- Rust MetadataExt.nlink用法及代碼示例
- Rust MetadataExt.st_atime用法及代碼示例
- Rust MaybeUninit.as_ptr用法及代碼示例
- Rust MetadataExt.uid用法及代碼示例
- Rust MetadataExt.st_ino用法及代碼示例
- Rust MaybeUninit.write_slice用法及代碼示例
- Rust MetadataExt.st_mode用法及代碼示例
- Rust MetadataExt.creation_time用法及代碼示例
- Rust Metadata.is_file用法及代碼示例
- Rust MetadataExt.st_rdev用法及代碼示例
- Rust MetadataExt.blocks用法及代碼示例
注:本文由純淨天空篩選整理自rust-lang.org大神的英文原創作品 Struct std::sync::Mutex。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。