Это что-то вроде хака.Во-первых, давайте посмотрим на код без этого:
mExitRequested.store(true);
mLooperCondition.notify_all();
Здесь возможны условия гонки.Какой-то другой код мог заметить, что mExitRequested
был ложным и начал ждать mLooperCondition
сразу после того, как мы вызвали notify_all
.
Гонка будет:
- Проверка других потоков
mExitRequested
, это false
. - Мы устанавливаем
mExitRequested
на true
. - Мы звоним
mLooperCondition.notify_all
. - Другой поток ожидает
mLooperCondition
. - Упс.Ожидание уведомления о том, что уже произошло.
Но для ожидания условной переменной необходимо удерживать связанный мьютекс.Так что это может произойти, только если какой-то другой поток содержал мьютекс mLooperLock
.Фактически, шаг 4 действительно был бы следующим: «Другой поток освобождает mLooperLock
и ждет mLooperCondition
.
Итак, чтобы эта гонка произошла, она должна произойти именно так:
- Другой поток получает
mLooperLock
. - Другие проверки потока
mExitRequested
, это false
. - Мы устанавливаем
mExitRequested
в true
. - Мы вызываем
mLooperCondition.notify_all
. - Другой поток ожидает
mLooperCondition
, освобождая mLooperLock
. - Упс. Ожидание уведомления о том, что уже произошло.
Итак, если мы изменим код на:
mExitRequested.store(true);
{ std::lock_guard<Mutex> lock(mLooperLock); }
mLooperCondition.notify_all();
Это гарантирует, что ни один другой поток не сможет проверить mExitRequested
и увидеть false
, а затем ждать mLooperCondition
. Поскольку другой поток должен будет удерживатьmLooperLock
блокировка всего процесса, что не может произойти, поскольку мы получили его в середине этого процесса.
Попытка еще раз:
- Другой поток получает
mLooperLock
. - Другие проверки потоков
mExitRequested
, это false
. - Мы устанавливаем
mExitRequested
в true
. - Приобретая и выпуская
nLooperLock
, мыне сделать любой прогресс вперед, пока другой поток не освободит mLooperLock
. - Мы вызываем
mLooperCondition.notify_all
.
Теперь либо другой поток блокирует условие, либо нет.Если это не так, нет проблем.Если это так, проблемы все равно нет, поскольку разблокировка mLooperLock
- это атомарная операция условной переменной «разблокировать и ждать», гарантирующая, что она увидит наше уведомление.