首页 文章

获取RwLock以进行读取并使其超出范围

提问于
浏览
2

我有一个定期调用回调函数的线程 . 根据状态,回调函数将获取与其他线程共享的资源 RwLock ,并使资源保持锁定,甚至超出回调函数的范围 . 然后它将再次依赖于状态在稍后的回调周期中再次释放资源 .

我的想法是将一个 Option<RwLockReadGuard<T>> 放入一个结构中,当资源未锁定时该结构为 None ,而当资源被锁定时为 Some(RwLockReadGuard<T>) .

不幸的是,我无法做到这一点 . 我必须在回调函数的线程外部设置包含 Option<RwLockReadGuard<T>> 的结构 . 即使在结构被移入线程 OptionNone 时,编译器也不允许我传递该选项,因为 the trait bound ``std::sync::RwLockReadGuard<'_, T>: std::marker::Send`` is not satisfied .

也许一些代码 . 我希望它足够自我解释 .

use std::thread;
use std::sync::{Arc, RwLock, RwLockReadGuard};


struct Handler<'a> {
        resource: Arc<RwLock<String>>,
        locked_resource: Option<RwLockReadGuard<'a, String>>,
        counter: usize,
}

impl<'a> Handler<'a> {
        fn callback(&'a mut  self) {
                println!("Callback {}", self.counter);
                if self.counter == 0 {
                        println!("Locking resource");
                        let res = self.resource.read().unwrap();
                        self.locked_resource = Some(res);
                }

                self.counter += 1;

                if self.counter == 100 {
                        println!("Releasing resource");
                        self.locked_resource = None;
                }

                if self.counter == 200 {
                        self.counter = 0;
                }
        }
}


fn main() {
        let resource = Arc::new(RwLock::new("foo".to_string()));

        let handler = Handler {
                resource: resource.clone(),
                locked_resource: None,
                counter: 0
        };

        // This gives E0277
        let thread = thread::spawn( move || {
                loop {
                        handler.callback();
                }
        });
}

1 回答

  • 3

    问题是:锁定和解锁需要在同一个线程上发生 . 例如,这是pthread的限制 .

    幸运的是,Rust类型系统足以表达这一点:通过使 RwLockReadGuard!Send ,它可以防止意外共享锁!所有冰雹锈!

    所以你可以在不同的回调函数中锁定和解锁......但是在同一个线程上 .

    在您的示例中,这就像在线程中移动 handler 的创建一样简单 . 在您的实际应用程序中,它可能会有点复杂,但请放心:编译器会牵着你的手;)

    fn main() {
        let resource = Arc::new(RwLock::new("foo".to_string()));
    
        let thread = thread::spawn( move || {
            let handler = Handler {
                    resource: resource,
                    locked_resource: None,
                    counter: 0
            };
    
            loop {
                    handler.callback();
            }
        });
    }
    

相关问题