Hameda169 понял это!
Я написал небольшой демонстрационный графический интерфейс с кнопкой «вкл» и «выкл», чтобы объяснить / запомнить концепцию в будущем.
Если вы закомментируете time.sleep(0.01)
после LOCK.release()
, кнопки графического интерфейса пользователя могут долго зависать, пока они пытаются получить блокировку.
Это также показывает, зачем вообще нужны блокировки. Если вы закомментируете with LOCK
в обратных вызовах on
и off
, вы очень скоро получите AttributeError
при нажатии кнопок.
# see what happens when there's no sleep AFTER release
# see what happens if on and off functions do not acquire the lock
import Tkinter as tk
import threading
import time
import ttk
class ON(object):
pass
class Printer(threading.Thread):
def __init__(self, *args, **kwargs):
super(Printer, self).__init__()
self.daemon = True
self.on = None
self.i = 0
def run(self):
while True:
LOCK.acquire()
if self.on is not None:
time.sleep(0.1) # make it very likely that self.on can be set to
# None from outside before trying to access
# dummy_attribute -> AttributeError w/o lock!
self.on.dummy_attribute # can error without lock
print(self.i)
self.i += 1
LOCK.release()
time.sleep(0.01) # must sleep after release, else lock can be
# acquired immediately again!
ROOT = tk.Tk()
PRINTER = Printer()
LOCK = threading.Lock()
def on():
with LOCK:
PRINTER.on = ON()
PRINTER.on.dummy_attribute = 'foo'
def off():
with LOCK:
PRINTER.on = None
ttk.Button(ROOT, text='on', command=on).grid()
ttk.Button(ROOT, text='off', command=off).grid()
if __name__ == '__main__':
PRINTER.start()
ROOT.mainloop()