本文简要介绍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。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。