use std::sync::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
#[inline]
pub fn lock_recover<T>(mutex: &Mutex<T>) -> MutexGuard<'_, T> {
mutex.lock().unwrap_or_else(|e| e.into_inner())
}
#[inline]
pub fn read_recover<T>(lock: &RwLock<T>) -> RwLockReadGuard<'_, T> {
lock.read().unwrap_or_else(|e| e.into_inner())
}
#[inline]
pub fn write_recover<T>(lock: &RwLock<T>) -> RwLockWriteGuard<'_, T> {
lock.write().unwrap_or_else(|e| e.into_inner())
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
#[test]
fn test_lock_recover_normal() {
let m = Mutex::new(42u64);
{
let mut g = lock_recover(&m);
*g += 1;
}
assert_eq!(*lock_recover(&m), 43);
}
#[test]
fn test_lock_recover_poisoned() {
let m = Arc::new(Mutex::new(1u64));
let m2 = Arc::clone(&m);
let _ = std::thread::spawn(move || {
let mut g = m2.lock().expect("首次加锁应成功");
*g = 99;
panic!("intentional poison for test");
})
.join();
assert_eq!(*lock_recover(&m), 99);
}
}