Уведомления

Группа в Telegram: @pythonsu

#1 Фев. 14, 2011 15:16:15

AlexandrR
От:
Зарегистрирован: 2010-10-12
Сообщения: 4
Репутация: +  0  -
Профиль   Отправить e-mail  

Нужна ли блокировка

Добрый день!
Поясните, правильно ли я использую блокировку (Lock()) в следующем коде или она не требуется:

import threading 

class _ServerThread(threading.Thread):
_lock = None
_daemon = None

def __init__(self):
threading.Thread.__init__(self)
self._lock = threading.Lock()

def run(self):
self._lock.acquire()
self._daemon=Daemon()
self._lock.release()
self._daemon.requestLoop() # Бесконечный цикл внутри

def stop(self):
self._lock.acquire()
self._daemon.shutdown()
self._lock.release()
При этом в особенности реализации Daemon() не вникаем и не знаем, насколько он thread-safe



Офлайн

#2 Фев. 14, 2011 16:54:37

nerijus
От:
Зарегистрирован: 2010-06-03
Сообщения: 93
Репутация: +  1  -
Профиль   Отправить e-mail  

Нужна ли блокировка

В run не нужен. А в stop, смотря что происходит в shutdown. Но скорее всего тоже не нужен (главное что бы stop вызывался один раз).



Офлайн

#3 Фев. 14, 2011 18:20:23

AlexandrR
От:
Зарегистрирован: 2010-10-12
Сообщения: 4
Репутация: +  0  -
Профиль   Отправить e-mail  

Нужна ли блокировка

Спасибо!
Не совсем понято только, причем здесь количество вызовов? Меня интересует блокировка как защита от одновременного обращения из разных потоков.



Офлайн

#4 Фев. 14, 2011 19:17:32

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Нужна ли блокировка

К чему - обращения? Какой объект вы защищаете?



Офлайн

#5 Фев. 14, 2011 19:50:24

nerijus
От:
Зарегистрирован: 2010-06-03
Сообщения: 93
Репутация: +  1  -
Профиль   Отправить e-mail  

Нужна ли блокировка

AlexandrR
Спасибо!
Не совсем понято только, причем здесь количество вызовов? Меня интересует блокировка как защита от одновременного обращения из разных потоков.
В этом то и дело, что если архитектура кривая, этот stop может быть вызван с двух разных потоков одновременно.



Офлайн

#6 Фев. 14, 2011 21:30:17

AlexandrR
От:
Зарегистрирован: 2010-10-12
Сообщения: 4
Репутация: +  0  -
Профиль   Отправить e-mail  

Нужна ли блокировка

Андрей Светлов
К чему - обращения? Какой объект вы защищаете?
Защищаю _daemon. Во всяком случае я пытаюсь это сделать, но может этого не нужно делать? Вот это и пытаюсь спросить.

nerijus
В этом то и дело, что если архитектура кривая, этот stop может быть вызван с двух разных потоков одновременно.
Так дело не в “кривой” архитектуре - это сервер, то есть запросы с клиентов идут асинхронно и независимо. Но можно допустить, что stop() будет вызван ровно 1 раз. Но может случиться так, что вызван он будет ровно в тот момент, когда выполнение метода run() в самом начале и тогда _daemon одновременно попытаются изменить два потока. А это же вроде не есть гут?



Офлайн

#7 Фев. 15, 2011 00:06:42

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Нужна ли блокировка

Создавайте Daemon в конструкторе.

th = _ServerThread()
th.start()
th.stop()
Что можно легко поймать?
th.run еще не начал выполнятся, блокировки нет.
th.stop() захватывает блокировку и вызывает self._daemon.shutdown() для еще не существующего атрибута _daemon. Ахтунг
th.run на этот момент добрался до блокировки. Вы игнорируете try-finally при использовании блоков, исключение из th.stop блокировку не снимает.
th.run ждет доступа к блоку вечно, поток никогда не завершится.

Теперь предположим, что вашему Daemon все же нужно выполнить конструктор в том же потоке, в котором будет крутится его requestLoop. Еще допустим, что _daemon.shutdown() можно вызвать только один раз, второй все поломает (это не всегда верно).

import threading 

class _ServerThread(threading.Thread):
_lock = None
_daemon = None

def __init__(self):
threading.Thread.__init__(self)
self._lock = threading.Lock()
self._condition = threading.Condition(self._lock)
self._started = False
self._stopping = False

def run(self):
try:
self._condition.acquire()
self._daemon=Daemon()
self._started = True
self._condition.notifyAll()
finally:
self._condition.release()
self._daemon.requestLoop() # Бесконечный цикл внутри

def stop(self):
try:
self._condition.acquire()
while not self._started:
self._condition.wait()
if not self._stopping:
self._daemon.shutdown()
self._stopping = True
finally:
self._condition.release()



Офлайн

#8 Фев. 15, 2011 06:04:52

AlexandrR
От:
Зарегистрирован: 2010-10-12
Сообщения: 4
Репутация: +  0  -
Профиль   Отправить e-mail  

Нужна ли блокировка

Андрей, спасибо!

Очень грамотный и обстоятельный ответ. И как раз именно то, что мне нужно. Все-таки 5 звезд в профиле неспроста.

P.S. Про заворачивание блокировок в try/finally я как-то забыл.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version