我有一个定期调用回调函数的线程 . 根据状态,回调函数将获取与其他线程共享的资源 RwLock
,并使资源保持锁定,甚至超出回调函数的范围 . 然后它将再次依赖于状态在稍后的回调周期中再次释放资源 .
我的想法是将一个 Option<RwLockReadGuard<T>>
放入一个结构中,当资源未锁定时该结构为 None
,而当资源被锁定时为 Some(RwLockReadGuard<T>)
.
不幸的是,我无法做到这一点 . 我必须在回调函数的线程外部设置包含 Option<RwLockReadGuard<T>>
的结构 . 即使在结构被移入线程 Option
是 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();
}
});
}
1 回答
问题是:锁定和解锁需要在同一个线程上发生 . 例如,这是pthread的限制 .
幸运的是,Rust类型系统足以表达这一点:通过使
RwLockReadGuard
为!Send
,它可以防止意外共享锁!所有冰雹锈!所以你可以在不同的回调函数中锁定和解锁......但是在同一个线程上 .
在您的示例中,这就像在线程中移动
handler
的创建一样简单 . 在您的实际应用程序中,它可能会有点复杂,但请放心:编译器会牵着你的手;)