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");
                }
            }
        }
    }
}
posted @ 2026-04-15 13:17  lxd670  阅读(15)  评论(0)    收藏  举报