classification
Title: Python quits on running tkinter code with threads
Type: behavior Stage:
Components: Documentation, Tkinter Versions: Python 3.5, Python 2.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: docs@python Nosy List: Sarbjit.singh, asvetlov, docs@python, serhiy.storchaka, terry.reedy
Priority: normal Keywords:

Created on 2012-12-31 03:23 by Sarbjit.singh, last changed 2016-02-24 08:44 by serhiy.storchaka.

Files
File name Uploaded Description Edit
debugstack.txt Sarbjit.singh, 2012-12-31 03:23 debugstack trace
tem.py terry.reedy, 2016-02-19 04:14 text code adapted to 3.x
Messages (6)
msg178642 - (view) Author: Sarbjit singh (Sarbjit.singh) Date: 2012-12-31 03:23
I have written a python tkinter code using threads so as the tkinter wizard updates automatically by tkinter mainloop running in the main thread and background process running in separate thread. But I noticed, that python crashes after some time when running the code. Moreover its random in nature but python crashes most of the time. I have written a small test code which can show this problem (My original code is similar to this but having some real processes and many other features, so I am sharing the test code).

######################################################################
 # Test Code for Tkinter with threads
import Tkinter
import threading
import Queue
import time

# Data Generator which will generate Data
def GenerateData(q):
    for i in range(1000000):
        #print "Generating Some Data, Iteration %s" %(i)
        time.sleep(0.01)
        q.put("Some Data from iteration %s. Putting this data in the queue for testing" %(i))

# Queue which will be used for storing Data
q = Queue.Queue()

def QueueHandler(widinst, q):
    linecount = 0
    while True:
        print "Running"
        if not q.empty():
            str = q.get()
            linecount = linecount + 1
            widinst.configure(state="normal")
            str = str + "\n"
            widinst.insert("end", str)
            if linecount > 100:
                widinst.delete('1.0', '2.0')
                linecount = linecount - 1
            widinst.see('end')
            widinst.configure(state="disabled")

# Create a thread and run GUI & QueueHadnler in it
tk = Tkinter.Tk()
scrollbar = Tkinter.Scrollbar(tk)
scrollbar.pack(side='right', fill='y' )
text_wid = Tkinter.Text(tk,yscrollcommand=scrollbar.set)
text_wid.pack()
t1 = threading.Thread(target=GenerateData, args=(q,))
t2 = threading.Thread(target=QueueHandler, args=(text_wid,q))
t2.start()
t1.start()

tk.mainloop()
######################################################################


TO REPRODUCE:

If you open this code in IDLE and run it, it will sometimes appeared to be in hang state. So to reproduce, modify the sleep time to 0.1 from 0.01 and run it. After this stop the application, and modify it back to 0.01, do save and run it. This time it will run and after some time, python will stop working. I am using windows 7 (64 bit).

NOTE:

I am getting different stack trace's when it crashes on console:
Please refer to the attached file for the stack traces.
msg179101 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2013-01-05 02:40
What you are doing appears to be unsupported (invalid). From
http://www.astro.washington.edu/users/rowen/TkinterSummary.html
"all Tkinter access must be from the main thread (or more precisely,
from the thread that calls the mainloop). Violating this is likely to
cause nasty and mysterious symptoms such as freezes and core dumps."

There have been at multiple posts on python-list and stack overflow from other users that have run into this limitation. I cannot find it in our tkinter docs, but I think perhaps it should be (even though not-thread-safe is the default for any python structure).
msg180000 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2013-01-15 03:12
We use 'crash' to mean a segfault (and core dump, on *nix) or the Windows equivalent. We avoid those if at all possible. A Python traceback is not a crash but a semi-graceful shutdown that has be planned for, given the circumstances. What is annoying here is getting a different exception (or at least message type) each time. I presume it depends on what data gets corrupted, and that is somewhat haphazard. The quote seems to be accurate.

I know little about threading, but if it were possible to detect tkinter access from other than the main thread (without excessive slowdown), then a consistent exception might be raised. But I am doubtful that this can be done sensibly. Hence a doc change seems like the best first step.
msg183770 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2013-03-08 23:01
From #11029: Doc about tkinter and treads should also give the alternative of using queue.queue to feed data from multiple threads.
See msg127316
msg260502 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2016-02-19 04:14
If I understand the test code, it creates the tk window in thread 0 (the main thread), generates data in thread 1, sends data via a queue to thread 2, which then inserts it into the Text widget.  I ran a 3.x version up to 34000 iterations.  When I comment out 'tk.mainloop()' or stop the mainloop with ^C, thread 2 stops (reproducibly) with

Exception in thread Thread-2:
Traceback (most recent call last):
  File "C:\Programs\Python35\lib\threading.py", line 914, in _bootstrap_inner
    self.run()
  File "C:\Programs\Python35\lib\threading.py", line 862, in run
    self._target(*self._args, **self._kwargs)
  File "F:\Python\mypy\tem.py", line 23, in QueueHandler
    widinst.configure(state="normal")
  File "C:\Programs\Python35\lib\tkinter\__init__.py", line 1330, in configure
    return self._configure('configure', cnf, kw)
  File "C:\Programs\Python35\lib\tkinter\__init__.py", line 1321, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
RuntimeError: main thread is not in main loop

I removed the spamming of Shell with 'running' and sped up the test code by reducing the queued and inserted text to the iteration number and reran to completion at 999999.  I retract my statement about all widget access in threads being unsupported.  At least some seems to be at least in 3.x.

Running the original test code above in 2.7.11 from IDLE and console both fail before 2000 iterations in my tries.

Sarbjit: I do not understand 'tkinter wizard'.

Serhiy: I am coming back to this after reading #11077.  Do you have any idea why this code runs in 3.x but eventually fails in 2.x?  If there anything to do, or just close?
msg260769 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2016-02-24 08:44
I don't know. I'm unable to reproduce the bug on Linux.
History
Date User Action Args
2016-02-24 08:44:22serhiy.storchakasetmessages: + msg260769
2016-02-19 04:14:39terry.reedysetversions: + Python 3.5, - Python 3.2, Python 3.3, Python 3.4
2016-02-19 04:14:16terry.reedysetfiles: + tem.py
nosy: + serhiy.storchaka, - gpolo, roger.serwy
messages: + msg260502

2013-03-08 23:01:40terry.reedysetmessages: + msg183770
2013-03-08 22:55:32terry.reedylinkissue11029 superseder
2013-01-15 03:12:20terry.reedysetmessages: + msg180000
title: Python crashes on running tkinter code with threads -> Python quits on running tkinter code with threads
2013-01-14 22:00:55asvetlovsetnosy: + asvetlov
2013-01-05 04:46:30terry.reedysetstatus: closed -> open
resolution: not a bug ->
2013-01-05 02:40:20terry.reedysetstatus: open -> closed

type: crash -> behavior
assignee: docs@python
components: + Documentation
versions: + Python 3.2, Python 3.3, Python 3.4
nosy: + gpolo, docs@python, roger.serwy, terry.reedy

messages: + msg179101
resolution: not a bug
2012-12-31 03:23:09Sarbjit.singhcreate