Concurrency 如何使用Condvar和Mutex监视更改

Concurrency 如何使用Condvar和Mutex监视更改,concurrency,locking,rust,race-condition,wakeup,Concurrency,Locking,Rust,Race Condition,Wakeup,我有一个共享的Vec。每当编写新的CacheChange时,我都想唤醒读者。我记得Condvar在谓词/情况准备就绪时,即当Vec被修改时,很适合发出信号 因此,我花了一些时间创建了一个监视器抽象来拥有Vec,并提供wait和lock语义 现在的问题是我不知道什么时候重置Condvar。给读者一个合理的时间来点击谓词并以自己的方式保持锁,什么是一个好方法?在关闭condvar之前?我是不是走错路了 这是锈迹代码,但更多的是多个读卡器之间精确并发访问/通知的基础问题 pub struct Moni

我有一个共享的
Vec
。每当编写新的
CacheChange
时,我都想唤醒读者。我记得
Condvar
在谓词/情况准备就绪时,即当
Vec
被修改时,很适合发出信号

因此,我花了一些时间创建了一个
监视器
抽象来拥有
Vec
,并提供
wait
lock
语义

现在的问题是我不知道什么时候重置
Condvar
。给读者一个合理的时间来点击谓词并以自己的方式保持锁,什么是一个好方法?在关闭condvar之前?我是不是走错路了

这是锈迹代码,但更多的是多个读卡器之间精确并发访问/通知的基础问题

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(())
    }
}
pub结构监视器(
sync::Arc
);
结构监视器{
数据:sync::Mutex,
谓词:(sync::Mutex,sync::Condvar)
}
impl监视器{
发布fn等待(&self)->结果{
让mut open=try!(self.0.predicate.0.lock());
打开{
open=try!(self.0.predicate.1.wait(open));
}
好(())
}
发布fn锁定(&self)->结果{
self.0.data.lock()
}
发布fn重置(&mut self)->结果{
让mut open=try!(self.0.predicate.0.lock());
*开=假;
好(())
}
发布fn唤醒所有(&mut self)->结果{
让mut open=try!(self.0.predicate.0.lock());
*开放=真实;
self.0.predicate.1.notify_all();
好(())
}
}
在第一次叫醒之后,我的读者可能会错过阅读。可能是因为当谓词被再次切换时,它们仍然持有数据锁。我在我的测试代码中只看到了一个读写器

然后是何时重置
监视器
的复杂问题,理想情况下,在所有读卡器都有机会查看数据后,监视器将被锁定。如果读卡器忽略其监视器,这可能会导致死锁问题(不能保证他们应该为每个唤醒调用提供服务)


我是否需要使用某种带超时的读卡器跟踪系统,并在监视器读取仍在服务时跟踪新数据何时到达?有没有我应该注意的现有范例?

最简单的解决方案是使用计数器而不是布尔值

struct MonitorInner<T> {
    data: sync::Mutex<T>,
    signal: sync::Condvar,
    counter: sync::AtomicUsize,
}
结构监视器{ 数据:sync::Mutex, 信号:sync::Condvar, 计数器:sync::AtomicUsize, }
然后,每次更新完成时,计数器都会递增。它永远不会重置,因此没有关于何时重置的问题


当然,这意味着读者应该记住上次醒来时计数器的值。

最简单的解决方案是使用计数器而不是布尔值

struct MonitorInner<T> {
    data: sync::Mutex<T>,
    signal: sync::Condvar,
    counter: sync::AtomicUsize,
}
结构监视器{ 数据:sync::Mutex, 信号:sync::Condvar, 计数器:sync::AtomicUsize, }
然后,每次更新完成时,计数器都会递增。它永远不会重置,因此没有关于何时重置的问题


当然,这意味着读者应该记住上次被唤醒时计数器的值。

它永远不会重置,每2^32或2^64递增一次。又名
time\u t
2038发行版^\u^@Shepmaster:是的,我希望
AtomicU64
是稳定的,因为64位计数器不能从1增量物理溢出(对于数学来说,1 inc/ns溢出需要约600年,或者5 GHz溢出需要约120年)。我可以将原子负载放入
wait()
当重新加载的计数更高时,线程将被唤醒。它永远不会被重置,而且每增加2^32或2^64次。又名
time\u t
2038发行版^\u^@Shepmaster:是的,我希望
AtomicU64
是稳定的,因为64位计数器不能从1增量物理溢出(对于数学来说,1 inc/ns溢出需要约600年,或者5 GHz溢出需要约120年)。我可以将原子负载放入
wait()
,当重新加载的计数较高时,线程将被唤醒。