如何使用Condvar和Mutex监控更改

时间:2016-10-26 05:53:16

标签: concurrency locking rust race-condition wakeup

我有一个共享Vec<CacheChange>。每当写一个新的CacheChange时,我想唤醒读者。我记得Condvar有助于在谓词/情境准备就绪时发出信号,即Vec被修改时。

所以我花了一些时间创建一个Monitor抽象来拥有Vec并提供waitlock语义。

现在的问题是我不知道何时重置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的复杂性,理想情况是在所有读者都有机会查看数据后它会被锁定。如果读者忽略了他们的监视器,这可能会导致死锁问题(不保证他们应该为每个唤醒呼叫提供服务)。

我是否需要使用某种具有超时功能的读卡器跟踪系统并跟踪新数据何时到达而显示器读取仍处于服务状态?我应该注意一个现有的范例吗?

1 个答案:

答案 0 :(得分:3)

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

struct MonitorInner<T> {
    data: sync::Mutex<T>,
    signal: sync::Condvar,
    counter: sync::AtomicUsize,
}

然后,每次更新完成后,计数器都会递增。它永远不会重置,因此毫无疑问何时重置。

当然,这意味着读者应该记住他们上一次被唤醒时的价值。