У меня есть общий Vec<CacheChange>
. Всякий раз, когда написано новое CacheChange
, я хочу пробудить читателей. Я помню, что Condvar
хорош для сигнализации, когда предикат/ситуация готова, а именно, когда изменено Vec
.Как отслеживать изменения с помощью Condvar и Mutex
Так что я потратил некоторое время на создание абстракции для Vec
и предоставил wait
и lock
семантику.
Проблема в том, что я не знаю, когда следует сбросить Condvar
. Каков хороший способ дать разумное количество времени читателям, чтобы поразить предикат и поработать над тем, чтобы держать замок? перед закрытием 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(())
}
}
После первого пробуждения мои читатели могут пропустить чтение. Вероятно, потому что они все еще держат блокировку данных, пока предикат снова был переключен. Я видел это в своем тестовом коде только с одним читателем и с одним автором.
Тогда возникает сложность, когда необходимо сбросить Monitor
, в идеале это будет заблокировано после того, как у всех читателей будет возможность посмотреть данные. Это может вызвать проблемы с блокировкой, если читатель игнорирует их мониторы (нет гарантии, что они должны обслуживать каждый звонок для пробуждения).
Должен ли я использовать какую-то систему слежения за читателем с тайм-аутами и отслеживать при поступлении новых данных во время просмотра мониторов? Существует ли существующая парадигма, о которой я должен знать?
* Он никогда не сбрасывается *, ну и каждые 2^32 или 2^64 приращения. AKA 'time_t' 2038 issue^_^ – Shepmaster
@Shepmaster: Да, я хочу, чтобы« AtomicU64 »был стабильным, поскольку 64-разрядный счетчик не может физически переполняться с 1-инкрементами (для математического наклона требуется ~ 600 лет для переполнения его 1 инк/нс или ~ 120 лет на частоте 5 ГГц). –
Я мог бы поставить атомную нагрузку в 'wait()', и поток проснется, когда перезагруженный счетчик будет выше. – xrl