Почему python требует от вас получить блокировку перед ожиданием условия - PullRequest
7 голосов
/ 07 июля 2019

В Python есть поточный объект с именем Condition, который блокирует поток, ожидающий, пока другой поток не вызовет notifiy() или notify_all().Однако перед вызовом метода wait() необходимо сначала вызвать acquire(), чтобы получить внутреннюю блокировку.Затем метод wait() снимает блокировку и ожидает уведомления, после чего он переходит к повторной блокировке, и вы можете запустить некоторый код, который должен быть поточно-ориентированным.Мой вопрос заключается в том, почему объект Condition не получает внутреннюю блокировку автоматически при вызове метода wait():

Документация по потокам Python

Другие методы должны вызыватьсяс соответствующей блокировкой удерживается.Метод wait() снимает блокировку и затем блокирует ее до тех пор, пока другой поток не пробудит ее, вызвав notify() или notify_all().После пробуждения wait() вновь получает блокировку и возвращается.Также можно указать тайм-аут.

Итак, в этом коде я получаю блокировку, метод wait немедленно освобождает его, а затем, после получения уведомления, снова получает его, а затем я в конце концов освобождаю его.

lock = threading.Lock()
condition = threading.Condition(lock=lock)
...
condition.lock()    # acquire the lock
condition.wait()    #  waiting for another thread to notify me
condition.release() # release the lock

почему вызов wait() просто не ждет, а затем получает блокировку, как только она получит уведомление. Я не понимаю, почему я получаю блокировку, чтобы она затем разблокировала

1 Ответ

5 голосов
/ 07 июля 2019

Если вы не удерживали блокировку, то, что вы ожидаете, может произойти до того, как вы начнете его ждать.

Скажем, у вас реализована очередь сообщений доморощенногос collections.deque, блокировкой и условной переменной.Поток A хочет прочитать элемент из очереди, поэтому он захватывает блокировку, проверяет деку, и нет элемента.Поток A вызывает condition.wait, чтобы дождаться, пока другой поток что-то вставит.

Поток B захватывает блокировку, вызывает deque.append(message) и вызывает condition.notify.Теперь поток A запланирован на пробуждение из-за вызова notify.

Представьте, может ли поток A снять блокировку перед вызовом wait.В этом случае поток B может добавить свое сообщение и вызвать condition.notify до того, как поток A начнет ждать.Нить А никогда не проснется.

...