2

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

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

不幸的是,我无法完成这项工作。我必须设置包含Option<RwLockReadGuard<T>>回调函数线程外部的结构。即使在将结构移入线程时Optionis None,编译器也不会让我通过该选项,因为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();
                }
        });
}
4

1 回答 1

3

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

幸运的是,Rust 类型系统的表现力足以对此进行建模:通过制作RwLockReadGuardbe !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();
        }
    });
}
于 2017-01-13T19:16:56.243 回答