Multithreading 获取用于读取的RwLock并使其超出范围

Multithreading 获取用于读取的RwLock并使其超出范围,multithreading,rust,rwlock,Multithreading,Rust,Rwlock,我有一个线程定期调用回调函数。根据状态,回调函数应获取与其他线程共享的资源的RwLock,并在回调函数范围之外保持资源锁定。然后,它将根据状态再次在稍后的回调周期中释放资源 我的想法是在一个结构中放入一个选项,当资源未锁定时,该结构将为None,当资源锁定时,该结构将为Some(RwLockReadGuard) 不幸的是,我做不到这一点。我必须在回调函数的线程之外设置包含选项的结构。即使在将结构移动到线程中时,选项为无,编译器也不会让我传递该选项,因为特性绑定``std::sync::RwLoc

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

我的想法是在一个结构中放入一个
选项
,当资源未锁定时,该结构将为
None
,当资源锁定时,该结构将为
Some(RwLockReadGuard)

不幸的是,我做不到这一点。我必须在回调函数的线程之外设置包含
选项的结构。即使在将结构移动到线程中时,
选项
,编译器也不会让我传递该选项,因为
特性绑定``std::sync::RwLockReadGuard>,
柜台:使用,
}
恳求{
fn回调(&'a mut self){
println!(“回调{}”,self.counter);
如果self.counter==0{
println!(“锁定资源”);
让res=self.resource.read().unwrap();
self.locked_resource=Some(res);
}
自计数器+=1;
如果self.counter==100{
println!(“发布资源”);
self.locked_资源=无;
}
如果self.counter==200{
self.counter=0;
}
}
}
fn main(){
让resource=Arc::new(RwLock::new(“foo.to_string()));
让handler=handler{
资源:resource.clone(),
锁定的资源:无,
柜台:0
};
//这就得到了E0277
让线程=线程::繁殖(移动| |{
环路{
callback();
}
});
}

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

幸运的是,Rust-type系统的表现力足以对此进行建模:通过使
rBlockReadGuard
be
!发送
,可防止意外共享锁!全是冰雹锈

因此,您可以在不同的回调函数中锁定和解锁。。。但是在同一条线上

在您的示例中,这与将
处理程序的创建移动到线程内部一样简单。在您的实际应用程序中,这可能有点复杂,但请放心:编译器会一直握着您的手;)


我已经想到了这一点,并尝试了你的解决方案。但它接着说,
处理程序可能活得不够长
。但无论如何,这不是一个选项,因为在我的实际项目中,我自己并不设置线程。我只是用回调函数交了一个trait对象,一个库启动了线程。有趣的错误,它与互斥锁无关。问题:你不能。关于你的问题,我很抱歉,但他们是规矩。你不能从一个线程锁定,从另一个线程解锁,并期望事情能正常工作:你必须用另一种方式设计你的程序。但它是同一个线程,不是吗?这是一个线程不断地反复调用
callback()
。我想让它在几个周期内保持锁定。@Johannesmeller:你确定吗?如果库使用线程池怎么办?如果库的当前版本不使用线程池,但下一个版本使用线程池(即,小心使用
safe
来绕过限制),该怎么办?在任何情况下,您当前都存在无法锁定兄弟字段的问题,解决该问题可能会引导您走向另一种更为适应的设计?
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();
                }
        });
}
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();
        }
    });
}