I'm having an issue with my GUI freezing, and I don't know why. The run method is not releasing the lock.
Demo program
import time
import threading
import Tkinter as tk
import ttk
LOCK = threading.Lock()
class Video(threading.Thread):
def __init__(self):
super(Video, self).__init__()
self.daemon = True
self.frame = tk.DoubleVar(root, value=0)
self.frames = 1000
def run(self):
while True:
with LOCK:
position = self.frame.get()
if position < self.frames:
position += 1
else:
position = 0
self.frame.set(position)
time.sleep(0.01)
root = tk.Tk()
video = Video()
root.minsize(500, 50)
def cb_scale(_):
with LOCK:
print('HELLO')
scale = ttk.Scale(
root, from_=video.frame.get(), to=video.frames, variable=video.frame,
command=cb_scale)
scale.grid(row=0, column=0, sticky=tk.EW)
root.columnconfigure(0, weight=1)
if __name__ == '__main__':
video.start()
root.mainloop()
Problem
Spam-clicking the progress bar freezes the program.
Attempts at debugging
-
I used
mttkinterby addingimport mttkinterto the import statements and the problem persists. The issue is the lock not being released. -
I inserted print statements to find out where exactly the program freezes.
Program with print statements:
from __future__ import print_function
import time
import threading
import Tkinter as tk
import ttk
def whichthread(say=''):
t = threading.current_thread()
print('{}{}'.format(say, t))
LOCK = threading.Lock()
class Video(threading.Thread):
def __init__(self):
super(Video, self).__init__()
self.daemon = True
self.frame = tk.DoubleVar(root, value=0)
self.frames = 1000
def run(self):
while True:
whichthread('run tries to acquire lock in thread: ')
with LOCK:
whichthread('run acquired lock in thread: ')
position = self.frame.get()
if position < self.frames:
position += 1
else:
position = 0
self.frame.set(position)
whichthread('run released lock in thread: ')
time.sleep(0.01)
root = tk.Tk()
video = Video()
root.minsize(500, 50)
def cb_scale(_):
whichthread('cb_scale tries to acquire lock in thread: ')
with LOCK:
whichthread('cb_scale acquired lock in thread: ')
print('HELLO')
whichthread('cb_scale released lock in thread: ')
scale = ttk.Scale(
root, from_=video.frame.get(), to=video.frames, variable=video.frame,
command=cb_scale)
scale.grid(row=0, column=0, sticky=tk.EW)
root.columnconfigure(0, weight=1)
if __name__ == '__main__':
video.start()
root.mainloop()
This produces the following output right before the program freezes:
...
run tries to acquire lock in thread: <Video(Thread-1, started daemon 140308329449216)>
run acquired lock in thread: <Video(Thread-1, started daemon 140308329449216)>
cb_scale tries to acquire lock in thread: <_MainThread(MainThread, started 140308415592256)>
This shows that for some reason, the run method does not release the lock.
- I tried to comment out lines in order to narrow the problem down.
Removing any of the two with LOCK statements fixes the issue. Unfortunately, in my real program the run and cb_scale function do something meaningful that requires locking.
Commenting out both the calls to get and set in run fixes the issue.
... and this is where I am stuck! :)
EDIT
Thanks to Mike - SMT I was able to track the problem down further.
Using
class DummyDoubleVar(object):
def get(self):
return 500
def set(self, _):
pass
and
self.frame = DummyDoubleVar()
in Video.__init__ prevents the program from freezing.
(Remember that the original program reliably freezes even with mttkinter. I am stumped what's going on here!)
from Why is this tkinter program freezing?
No comments:
Post a Comment