我有一个程序,将可变状态隐藏在RwLock后面。我想做的是,当将它可变地借用(RW_LOCK.write()
)时,它应该执行某些操作(即,尝试写入文件,清理rwlock后面的数据等)
例如:
let DATA: RwLock<Data> = RwLock::new(Data { content: Default::default() } );
fn do_something() {
let mut state = DATA.write().unwrap();
state.change(5);
// ...
// Here, just before `state` goes out of scope (where it gets dropped and `RwLock` will allow
// other threads read/write access to `Data`, I would like for `RwLock` to auto-run `state.cleanup()`.
}
是否可以执行此操作,还是必须重新实现RwLock
?
答案 0 :(得分:2)
您可以使用包装类型:
use std::ops::{Deref, DerefMut, Drop};
use std::sync::{RwLock, RwLockWriteGuard};
type CleanupClosure<'a> = Fn(&mut RwLockWriteGuard<'a, Data>);
struct Data {
content: String,
}
impl Data {
fn change(&mut self, num: i32) {
println!("Changed to {}", num);
self.content = num.to_string();
}
}
struct RwLockWriteWrapper<'a, F: CleanupClosure<'a>>(RwLockWriteGuard<'a, Data>, F);
impl<'a, F: CleanupClosure<'a>> Deref for RwLockWriteWrapper<'a, F> {
type Target = RwLockWriteGuard<'a, Data>;
fn deref(&self) -> &RwLockWriteGuard<'a, Data> {
&self.0
}
}
impl<'a, F: CleanupClosure<'a>> DerefMut for RwLockWriteWrapper<'a, F> {
fn deref_mut(&mut self) -> &mut RwLockWriteGuard<'a, Data> {
&mut self.0
}
}
impl<'a, F: CleanupClosure<'a>> Drop for RwLockWriteWrapper<'a, F> {
fn drop(&mut self) {
println!("Cleaning up!");
self.1(&mut self.0)
}
}
fn main() {
let data: RwLock<Data> = RwLock::new(Data {
content: "Start".to_owned(),
});
do_something(&data);
do_something(&data);
}
fn do_something(data: &RwLock<Data>) {
// Write your own cleanup logic here
let mut state = RwLockWriteWrapper(data.write().unwrap(), |state| {
state.content = "Cleaned up".to_owned()
});
println!("do_something start: {}", state.content);
state.change(5);
println!("do_something after change: {}", state.content);
} // Automatically run cleanup here
它确实要求您在调用.write()
时记住包装该类型。您可以将RwLock
本身包装成另一种类型,该类型也将返回RwLockWriteWrapper
以使其自动化。
这确实变得很冗长,所以我发现了a crate that impls the deref trait for you。
我仍然不确定标题中提到的闭包是什么。
答案 1 :(得分:0)
您可以创建实现Drop
的包装器:
struct CleanOnDrop<D, F>
where
F: FnOnce(&mut D),
{
data: D,
cleanup: Option<F>,
}
impl<D, F> CleanOnDrop<D, F>
where
F: FnOnce(&mut D),
{
pub fn new(data: D, cleanup: F) -> Self {
Self { data, cleanup: Some(cleanup) }
}
}
impl<D, F> Drop for CleanOnDrop<D, F>
where
F: FnOnce(&mut D)
{
fn drop(&mut self) {
if let Some(mut cleanup) = self.cleanup.take() {
cleanup(&mut self.data);
}
}
}
为方便起见,您可能还希望实现Deref
和DerefMut
,以便可以直接在其上调用方法:
use std::ops::{Deref, DerefMut};
impl<D, F> Deref for CleanOnDrop<D, F>
where
F: FnOnce(&mut D),
{
type Target = D;
fn deref(&self) -> &D {
&self.data
}
}
impl<D, F> DerefMut for CleanOnDrop<D, F>
where
F: FnOnce(&mut D),
{
fn deref_mut(&mut self) -> &mut D {
&mut self.data
}
}
像这样使用包装器:
let data = RwLock::new(CleanOnDrop::new(
Data {
content: Default::default(),
},
|state| {
state.cleanup();
},
));