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();
}
});
}