我有一个共享 Vec<CacheChange>
.每当一个新的CacheChange
写的我想唤醒读者。我记得一个Condvar
有利于在谓词/情况准备就绪时发出信号,即当 Vec
时已修改。
所以我花了一些时间创建了一个 Monitor
拥有 Vec
的抽象并提供wait
和 lock
语义。
现在的问题是我不知道什么时候重置Condvar
.给读者合理的时间来命中谓词并努力持有锁的好方法是什么?在关闭 condvar 之前?我接近Condvar
走错路了吗?
这是 Rust 代码,但这更多的是关于多个读者之间精确并发访问/通知的基础问题。
pub struct Monitor<T>(
sync::Arc<MonitorInner<T>>
);
struct MonitorInner<T> {
data: sync::Mutex<T>,
predicate: (sync::Mutex<bool>, sync::Condvar)
}
impl<T> Monitor<T> {
pub fn wait(&self) -> Result<(),sync::PoisonError<sync::MutexGuard<bool>>> {
let mut open = try!(self.0.predicate.0.lock());
while !*open {
open = try!(self.0.predicate.1.wait(open));
}
Ok(())
}
pub fn lock(&self) -> Result<sync::MutexGuard<T>, sync::PoisonError<sync::MutexGuard<T>>> {
self.0.data.lock()
}
pub fn reset(&mut self) -> Result<(),sync::PoisonError<sync::MutexGuard<bool>>> {
let mut open = try!(self.0.predicate.0.lock());
*open = false;
Ok(())
}
pub fn wakeup_all(&mut self) -> Result<(),sync::PoisonError<sync::MutexGuard<bool>>> {
let mut open = try!(self.0.predicate.0.lock());
*open = true;
self.0.predicate.1.notify_all();
Ok(())
}
}
在第一次叫醒电话后,我的读者可能会错过阅读。可能是因为当谓词再次切换时它们仍然持有数据锁。我在我的测试代码中看到了这一点,只有一个读者和一个作者。
然后是何时重置 Monitor
的复杂问题, 理想情况下,在所有读者都有机会查看数据后,它会被锁定。如果读者忽略他们的监视器(不保证他们应该为每个唤醒调用服务),这可能会导致死锁问题。
我是否需要使用某种具有超时功能的读者跟踪系统,并在新数据到达时跟踪监视器读取仍在服务中?是否有我应该注意的现有范例?
最佳答案
最简单的解决方案是使用计数器而不是 bool 值。
struct MonitorInner<T> {
data: sync::Mutex<T>,
signal: sync::Condvar,
counter: sync::AtomicUsize,
}
然后,每次更新完成时,计数器都会递增。它从不重置,因此不存在何时重置的问题。
当然,这意味着读者应该记住上次被唤醒时计数器的值。
关于concurrency - 如何使用 Condvar 和 Mutex 监控变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40254677/