std::sync::RwLock
创建RwLock
use std::sync::RwLock;
fn main() {
let rw_lock = RwLock::new(5);
println!("{:?}", rw_lock);
}
RwLock { data: 5, poisoned: false, .. }
访问数据
get_mut
返回对底层数据的可变引用
如果
RwLock中毒,此函数将返回错误。 每当 writer 在持有排他锁时发生 panic 时,RwLock就会中毒。
use std::sync::RwLock;
fn main() {
let mut rw_lock = RwLock::new(5);
// 获取内部值的可变引用
let s = rw_lock.get_mut().unwrap();
*s = 10;
println!("{:?}", rw_lock);
}
RwLock { data: 10, poisoned: false, .. }
into_inner
消耗这个
RwLock,返回底层数据。如果
RwLock中毒,此函数将返回错误。每当 writer 在持有排他锁时发生 panic 时,RwLock就会中毒。
use std::sync::RwLock;
fn main() {
let mut rw_lock = RwLock::new(5);
let v = rw_lock.into_inner().unwrap();
println!("v: {}", v);
// println!("{:?}", rw_lock); 已经被消耗了,不能使用
}
v: 5
读写加锁
读取
read
阻塞线程,获取
RwLockReadGuard
use std::sync::{RwLock, Arc};
use std::thread;
use std::time::Duration;
fn main() {
let arc_rw_lock = Arc::new(RwLock::new(5));
let arc_clone1 = arc_rw_lock.clone();
let arc_clone2 = arc_rw_lock.clone();
let h1 = thread::spawn(move || {
for i in 0..6 {
thread::sleep(Duration::from_millis(500));
let read_guard = arc_clone1.read().unwrap();
// 解引用获取数据
let s = *read_guard;
println!("read s[{}]: {}", i, s);
}
});
let h2 = thread::spawn(move || {
for i in 0..3 {
thread::sleep(Duration::from_secs(1));
let mut write_guard = arc_clone2.write().unwrap();
*s += 1;
println!("write s[{}]: {}", i, s);
}
});
h1.join().unwrap();
h2.join().unwrap();
}
read s[0]: 5
write s[0]: 6
read s[1]: 6
read s[2]: 6
write s[1]: 7
read s[3]: 7
read s[4]: 7
write s[2]: 8
read s[5]: 8
try_read
尝试获取
RwLockReadGuard。如果访问是加锁的,则返回std::sync::TryLockError::WouldBlock。如果
RwLock中毒,此函数将返回Poisoned错误
use std::sync::{RwLock, Arc};
use std::thread;
use std::time::Duration;
fn main() {
let arc_rw_lock = Arc::new(RwLock::new(5));
let arc_clone1 = arc_rw_lock.clone();
let arc_clone2 = arc_rw_lock.clone();
let h1 = thread::spawn(move || {
for i in 0..6 {
thread::sleep(Duration::from_secs(1));
match arc_clone1.try_read() {
Ok(n) => println!("read s[{}]: {}", i, n),
Err(e) => println!("read [{}]: {:?}", i, e)
};
}
});
let h2 = thread::spawn(move || {
for i in 0..3 {
let mut rw_lock_write_guard = arc_clone2.write().unwrap();
*rw_lock_write_guard += 1;
println!("write s[{}]: {}", i, rw_lock_write_guard);
thread::sleep(Duration::from_secs(1));
}
});
h1.join().unwrap();
h2.join().unwrap();
}
write s[0]: 6
read [0]: "WouldBlock"
write s[1]: 7
read [1]: "WouldBlock"
write s[2]: 8
read [2]: "WouldBlock"
read s[3]: 8
read s[4]: 8
read s[5]: 8
写入
write
阻塞当前线程,直到它可以被获取。在
writer阶段panic时RwLock就会中毒。如果
RwLock中毒,此函数将返回错误。
use std::sync::{Arc, RwLock};
use std::thread;
use std::time::Duration;
fn main() {
let arc_rw_lock = Arc::new(RwLock::new(5));
let arc_clone1 = arc_rw_lock.clone();
let arc_clone2 = arc_rw_lock.clone();
// 线程一写入
let h1 = thread::spawn(move || {
for i in 0..3 {
thread::sleep(Duration::from_secs(1));
let mut write_guard = arc_clone1.write().unwrap();
*write_guard += 2;
println!("write h1[{}]: {}", i, write_guard);
}
});
// 线程二写入
let h2 = thread::spawn(move || {
for i in 0..3 {
thread::sleep(Duration::from_secs(1));
let mut write_guard = arc_clone2.write().unwrap();
*write_guard += 1;
println!("write h2[{}]: {}", i, write_guard);
}
});
h1.join().unwrap();
h2.join().unwrap();
}
write h2[0]: 6
write h1[0]: 8
write h1[1]: 10
write h2[1]: 11
write h1[2]: 13
write h2[2]: 14
中毒
只有当write时panic,RwLock才会中毒
write的err只有PoisonError一中类型,write会等待,所以不会报WouldBlock的错误
use std::sync::{Arc, RwLock};
use std::thread;
fn main() {
let arc_rw_lock = Arc::new(RwLock::new(5));
let arc_clone1 = arc_rw_lock.clone();
let _ = thread::spawn(move || {
let _write_guard = arc_clone1.write().unwrap();
// 报错会设置中毒状态
panic!("error");
})
.join();
match arc_rw_lock.read() {
Ok(guard) => {
println!("read[OK] s: {}", *guard);
},
Err(err) => {
// err是PoisonError
// PoisonError.into_inner() 消费PoisonError获取内部数据
// PoisonError.get_ref() 获取内部数据引用
// PoisonError.get_mut() 获取内部数据可变引用
println!("read[Err] s: {:?}", err);
println!("read[Err] poisoned: {}", arc_rw_lock.is_poisoned());
}
}
}
thread '<unnamed>' (73234142) panicked at src/main.rs:10:9:
error
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
read[Err] s: PoisonError { .. }
read[Err] poisoned: true
try_write
尝试获取
RwLockWriteGuard。如果访问是加锁的,则返回WouldBlock。
如果RwLock中毒,此函数将返回Poisoned错误
需要导入std::sync::TryLockError::{Poisoned, WouldBlock}
use std::sync::{RwLock, Arc};
use std::sync::TryLockError::{Poisoned, WouldBlock};
use std::thread;
use std::time::Duration;
fn main() {
let arc_rw_lock = Arc::new(RwLock::new(5));
let arc_clone1 = arc_rw_lock.clone();
let arc_clone2 = arc_rw_lock.clone();
let h1 = thread::spawn(move || {
for i in 0..3 {
let mut s = arc_clone1.write().unwrap();
*s += 2;
println!("h1 {:?}", s);
if i == 2 {
panic!("test err")
}
thread::sleep(Duration::from_secs(1));
}
});
let h2 = thread::spawn(move || {
for _i in 0..3 {
match arc_clone2.try_write() {
Ok(mut w) => {
*w += 1;
println!("h2 {:?}", w);
},
Err(e) => {
match e {
// 锁被占用,拿不到
WouldBlock => {
println!("h2[WouldBlock]: {:?}", e);
},
// 中毒了
Poisoned(p_err) => {
println!("h2[Poisoned]: {:?}", p_err);
}
}
}
}
thread::sleep(Duration::from_secs(1));
}
});
let _ = h1.join();
let _ = h2.join();
}
h1 7
h2[WouldBlock]: "WouldBlock"
h1 9
h2[WouldBlock]: "WouldBlock"
h1 11
thread '<unnamed>' (73243968) panicked at src/main.rs:16:17:
test err
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
h2[Poisoned]: PoisonError { .. }
中毒
- RwLock 中毒规则
- write 锁 panic → 中毒(数据可能被改坏)
- read 锁 panic → 不中毒(只读,数据安全)
is_poisoned
判断是否中毒, 在arc_rw_lock上判断
use std::sync::{RwLock, Arc};
use std::thread;
fn main() {
let arc_rw_lock = Arc::new(RwLock::new(5));
let arc_clone1 = arc_rw_lock.clone();
let _ = thread::spawn(move || {
let mut s = arc_clone1.write().unwrap();
panic!("error");
}).join();
let s = arc_rw_lock.is_poisoned();
println!("is_poisoned: {:?}", s);
}
thread '<unnamed>' (18968766) panicked at src/main.rs:9:9:
error
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
is_poisoned: true
处理中毒
use std::sync::{RwLock, Arc};
use std::sync::TryLockError::{Poisoned, WouldBlock};
use std::thread;
fn main() {
let arc_rw_lock = Arc::new(RwLock::new(5));
let arc_clone1 = arc_rw_lock.clone();
let _ = thread::spawn(move || {
let mut s = arc_clone1.write().unwrap();
*s += 2;
// 报错,自动标记中毒
panic!("test err")
}).join();
match arc_rw_lock.try_write() {
Ok(mut w) => {
println!("{}", w);
},
Err(poison_err) => {
match poison_err {
Poisoned(p) => {
println!("p: {:?}", p);
println!("is_poisoned: {}", arc_rw_lock.is_poisoned()); // 用arc_rw_lock判断是否被poison
println!("v: {}", p.into_inner()); // 消费PoisonError获取内部数据
},
WouldBlock => {
println!("Would Block");
}
}
}
}
}
thread '<unnamed>' (19029556) panicked at src/main.rs:12:9:
test err
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
p: PoisonError { .. }
is_poisoned: true
v: 7
清除中毒
use std::sync::{RwLock, Arc};
use std::sync::TryLockError::{Poisoned, WouldBlock};
use std::thread;
fn main() {
let arc_rw_lock = Arc::new(RwLock::new(5));
let arc_clone1 = arc_rw_lock.clone();
let _ = thread::spawn(move || {
let mut s = arc_clone1.write().unwrap();
*s += 2;
panic!("test err")
}).join();
match arc_rw_lock.try_write() {
Ok(mut gruard) => {
*gruard += 1;
println!("{}", *gruard);
},
Err(poison_err) => {
match poison_err {
Poisoned(p) => {
println!("p: {:?}", p);
println!("is_poisoned: {}", arc_rw_lock.is_poisoned());
// 获取内部数据引用
println!("v: {}", p.get_ref());
// 清除中毒标记(arc_rw_lock)
arc_rw_lock.clear_poison();
println!("is_poisoned: {}", arc_rw_lock.is_poisoned());
},
WouldBlock => {
println!("Would Block");
}
}
}
}
}

浙公网安备 33010602011771号