Saturday, 9 November 2019

Why is this tkinter program freezing?

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

  1. I used mttkinter by adding import mttkinter to the import statements and the problem persists. The issue is the lock not being released.

  2. 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.

  1. 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