2016-12-23 7 views
1

У меня есть std::condition_variable_any, который ждет пользовательской блокировки, которая представляет собой композицию из двух мьютексов (одна std::mutex и одна с общим доступом - std::shared_mutex). Операция unlock() просто разблокирует оба взаимного доступа.Условие переменной ожидания при множественных взаимных ошибках

Например (псевдокод):

mutex mutex1; 
shared_mutex mutex2; 
condition_variable_any cv; 
// acquiring the locks 
DualLock lock(unique_lock(mutex1), shared_lock(mutex2)); 
// waiting 
cv.wait(lock); 

cv.wait() должен атомарно разблокировки как mutex1 и mutex2, и положить нить спать, пока cv не получает уведомление.

Он все еще гарантирует, что нить спала и прислушивалась к уведомлению о переменной состояния, как только какой-либо из mutex1 или mutex2 разблокирован?

Возможно, что один мьютекс разблокирован, а второй поток блокирует его, отправляет уведомление, но этот первый поток еще не спал и не слушал. Таким образом, уведомление никогда не прибывало и никакого пробуждения не происходит.

+0

Если 'DualLock' не использует' станд :: lock' для блокировки мьютексов вы находитесь в опасности тупика. Ваш псевдокод выглядит так, будто вам угрожает тупиковая ситуация в линии, создающей «DualLock». –

ответ

2

Если DualLock отвечает требованиям BasicLockable, тогда код будет действовать в надежде. Если нет, это не так.

BasicLockable ссылка here

Так что уведомление не пришло, и нет пробуждения не происходит.

Этого никогда не может быть, если переменные условия используются должным образом. Пробуждение переменной условия не может быть интерпретировано как сигнал события, так как документация condition_variable объясняет, что возможны побочные пробуждения.

В лучшем случае уведомление является признаком того, что сейчас самое подходящее время для проверки условия, в котором вы ожидаете (и вы можете сделать это в безопасном знании того, что тест защищен мьютексом).

Состояние состояния и состояние блокировки текущего потока - две отдельные проблемы.

Вот лучший пример (предполагается, что модели DualLock BasicLockable правильно):

bool condition_met = false; 

mutex mutex1; 
shared_mutex mutex2; 
condition_variable_any cv; 
// acquiring the locks 
DualLock lock(unique_lock(mutex1), shared_lock(mutex2)); 
while(!condition_met) 
{ 
    // waiting 
    cv.wait(lock); 
} 
// whatever happens, you have the lock here 

// ...work 

lock.unlock(); 

Ваш Уведомитель уведомит так:

DualLock lock(unique_lock(mutex1), shared_lock(mutex2)); 
condition_met = true; 
lock.unlock();  // note the order: unlock mutex first... 
cv.notify_all(); // ...then notify the condition variable 
+0

Итак, если 'cv.notify_all()' вызывается, а 'cv.wait() -> DualLock :: unlock()' все еще выполняется в ожидающем потоке (после того, как он только разблокировал один из двух мьютексов), он все еще гарантировано, что 'wait' не начнет спать, а вместо этого немедленно вернется? – tmlen

+0

@tmlen метод блокировки вашего пользовательского мьютекса должен вести себя согласно концепции (I.e. Полностью блокируйте мьютексы, блокируйте их или генерируйте исключение). Если вы получите это право, вышеуказанный код всегда будет работать. Усложнение здесь заключается в реализации вашей двойной блокировки, а не в cv. –

Смежные вопросы