Tkinter deadlock on graceful exit

Terry Reedy tjreedy at udel.edu
Wed May 30 21:42:47 EDT 2012


On 5/30/2012 6:19 PM, Matteo Landi wrote:
> On May/28, Matteo Landi wrote:
>> Hi list,
>> recently I started to work on an application [1] which makes use of the Tkinter
>> module to handle interaction with the user.  Simply put, the app is a text
>> widget displaying a file filtered by given criteria, with a handy feature that
>> the window is raised each time a new line is added to the widget.
>>
>> The application mainly consists of three threads:  the first one, the file
>> processor, reads the file, filters the lines of interest, and pushes them into
>> a shared queue (henceforth `lines_queue`);  the second one, the gui_updater,
>> pops elements from `lines_queue`, and schedule GUI updates using the
>> `after_idle` method of the Tkinter module;  finally the last one, the worker
>> spawner, receives commands by the gui (by means of a shared queue,
>> `filters_queue`), and drives the application, terminating or spawning new
>> threads.
>>
>> For example, let's see what happens when you start the application, fill the
>> filter entry and press Enter button:
>> 1 the associated even handler is scheduled (we should be inside the Tkinter
>>    mainloop thread), and the filter is pushed into `filters_queue`;
>> 2 the worker spawner receives the new filter, terminate a possibly running
>>    working thread, and once done, create a new file processor;
>> 3 the file processor actually processes the file and fills the `lines_queue`
>>    with the lines matching given filter;
>> 4 the gui updater schedules GUI updates as soon as items are pushed into
>>    `lines_queue`
>> 5 Tkinter mainloop thread updates the gui when idle
>>
>> What happens when the main window is closed?  Here is how I implemented the
>> graceful shutdown of the app:
>> 1 a quit event is scheduled and a _special_ message is pushed into both
>>    `filter_queue` and `lines_queue`
>> 2 the gui updater threads receives the _special_ message, and terminates
>> 3 the worker spawner receives the message, terminates the working thread and
>>    interrupts her execution.
>> 4 Tk.quit() is called after the quit event handler, and we finally quit the
>>    mainloop
>>
>> Honestly speaking, I see no issues with the algorithm presented above;  however,
>> if I close the window in the middle of updates of the text widget, the
>> applications hangs indefinitely.  On the other hand, everything works as
>> expected if I close the app when the file processor, for example, is waiting for
>> new content to filter.
>>
>> I put some logging messages to analyze the deadlock (?!), and noticed that both
>> the worker spawner and the file processor are terminated correctly.  The only
>> thread still active for some strange reasons, is the gui updater.
>>
>> Do you see anything wrong with the description presented above?  Please say so,
>> because I can't figure it out!

Since no-one else answered, I will ask some questions based on little 
tkinter experience, no thread experience, and a bit of python-list reading.

1. Are you only using tkinter in one thread? (It seems like so from the 
above)?

2. Is root.destroy getting called, as in 24.1.2.2. A Simple Hello World 
Program in the most recent docs? (I specify 'most recent' because that 
example has been recently revised because the previous version sometimes 
left tkinter hanging for one of the code paths, perhaps similar to what 
you describe.

3. Have you tried making the gui thread the master thread? (I somehow 
expect that the gui thread should be the last to shut down.)

--
Terry Jan Reedy




More information about the Python-list mailing list