Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash, 2.7.1, Tkinter and threads and line drawing #55238

Closed
PythonInTheGrass mannequin opened this issue Jan 27, 2011 · 9 comments
Closed

Crash, 2.7.1, Tkinter and threads and line drawing #55238

PythonInTheGrass mannequin opened this issue Jan 27, 2011 · 9 comments
Labels
docs Documentation in the Doc dir type-bug An unexpected behavior, bug, or error

Comments

@PythonInTheGrass
Copy link
Mannequin

PythonInTheGrass mannequin commented Jan 27, 2011

BPO 11029
Nosy @terryjreedy, @briancurtin
Superseder
  • bpo-16823: Python quits on running tkinter code with threads
  • Files
  • TkinterCrash.py: script to crash Tkinter
  • TkinterCrash2.py
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2013-03-08.22:55:32.983>
    created_at = <Date 2011-01-27.17:01:03.653>
    labels = ['type-bug', 'docs']
    title = 'Crash, 2.7.1, Tkinter and threads and line drawing'
    updated_at = <Date 2015-05-24.15:31:13.235>
    user = 'https://bugs.python.org/PythonInTheGrass'

    bugs.python.org fields:

    activity = <Date 2015-05-24.15:31:13.235>
    actor = 'terry.reedy'
    assignee = 'docs@python'
    closed = True
    closed_date = <Date 2013-03-08.22:55:32.983>
    closer = 'terry.reedy'
    components = ['Documentation']
    creation = <Date 2011-01-27.17:01:03.653>
    creator = 'PythonInTheGrass'
    dependencies = []
    files = ['20549', '20576']
    hgrepos = []
    issue_num = 11029
    keywords = []
    message_count = 9.0
    messages = ['127201', '127222', '127243', '127307', '127316', '127344', '183769', '243978', '243988']
    nosy_count = 6.0
    nosy_names = ['terry.reedy', 'brian.curtin', 'cgohlke', 'docs@python', 'PythonInTheGrass', 'Jackmoo']
    pr_nums = []
    priority = 'normal'
    resolution = 'duplicate'
    stage = None
    status = 'closed'
    superseder = '16823'
    type = 'behavior'
    url = 'https://bugs.python.org/issue11029'
    versions = ['Python 2.7', 'Python 3.2']

    @PythonInTheGrass
    Copy link
    Mannequin Author

    PythonInTheGrass mannequin commented Jan 27, 2011

    Running on dual core Windows XP.

    The function should draw a parabolicish shape for each click on launch. But if you click Launch over and over, very fast, you get bizarre crashes instead: Python.exe has encoutered a problem, yadda. tcl85.dll. It rarely takes many clicks.

    Apologies for the coding style; this has been hacked down from a larger app.

    In the console window:

    Exception in thread Thread-5:
    Traceback (most recent call last):
      File "C:\Python27\lib\threading.py", line 530, in __bootstrap_inner
        self.run()
      File "C:\Documents and Settings\mayos\Desktop\PMT2\MyProjects\TkinterCrash.py"
    , line 47, in run
        self.app.arrival_122((self.target, y, z))
      File "C:\Documents and Settings\mayos\Desktop\PMT2\MyProjects\TkinterCrash.py"
    , line 100, in arrival_122
        self.label.config(text= str(message[0])+ " " + str(message[1]))
      File "C:\Python27\lib\lib-tk\Tkinter.py", line 1202, in configure
        return self._configure('configure', cnf, kw)
      File "C:\Python27\lib\lib-tk\Tkinter.py", line 1193, in _configure
        self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
    TclError: invalid command name "source C:/Python27/tcl/tk8.5/menu.tcl"
    
    Exception in thread Thread-4:
    Traceback (most recent call last):
      File "C:\Python27\lib\threading.py", line 530, in __bootstrap_inner
        self.run()
      File "C:\Documents and Settings\mayos\Desktop\PMT2\MyProjects\TkinterCrash.py"
    , line 47, in run
        self.app.arrival_122((self.target, y, z))
      File "C:\Documents and Settings\mayos\Desktop\PMT2\MyProjects\TkinterCrash.py"
    , line 125, in arrival_122
        self.graph.create_line(self.trackCoordinates[tn], new_yz)
      File "C:\Python27\lib\lib-tk\Tkinter.py", line 2201, in create_line
        return self._create('line', args, kw)
      File "C:\Python27\lib\lib-tk\Tkinter.py", line 2189, in _create
        *(args + self._options(cnf, kw))))
    TclError: invalid command name "line"

    Also saw:
    File "C:\Python27\lib\lib-tk\Tkinter.py", line 2201, in create_line
    return self._create('line', args, kw)
    File "C:\Python27\lib\lib-tk\Tkinter.py", line 2189, in _create
    *(args + self._options(cnf, kw))))
    TclError: bad option "665.4400009999997": must be addtag, bbox, bind, canvasx, canvasy, cget, configure, coords, create, dchars, delete, dtag, find, focus, gettags, icursor, index, insert, itemcget, itemconfigure, lower, move, postscript, raise, scale, scan, select, type, xview, or yview

    @PythonInTheGrass PythonInTheGrass mannequin added topic-tkinter type-crash A hard crash of the interpreter, possibly with a core dump labels Jan 27, 2011
    @PythonInTheGrass
    Copy link
    Mannequin Author

    PythonInTheGrass mannequin commented Jan 27, 2011

    To make this more interesting, I'm trying to push for adoption of Python at a scripting tool where I work, and I uncovered this crasher in example code I was about to hand out, under the heading of "look how easy Python is". For obvious reasons I'm holding off on handing out the example; I won't get far selling Python if it crashes when drawing lines... if this is a result of something boneheaded I did, please slap me upside the head ASAP. Conversely if there's a quick fix possible, that will speed Python adoption where I work... thanks.

    @cgohlke
    Copy link
    Mannequin

    cgohlke mannequin commented Jan 28, 2011

    Tkinter is not thread safe. You are changing UI elements from a thread that is not the main thread. Use a Queue as described at http://effbot.org/zone/tkinter-threads.htm.

    @PythonInTheGrass
    Copy link
    Mannequin Author

    PythonInTheGrass mannequin commented Jan 28, 2011

    OK, now all calls to Tkinter are funneled to a single thread, through a queue. (Technically there are two threads in Tkinter - one is parked in .mainloop(), the other makes a call to Canvas.create_line and a call to Label.config.) Different crash, but still a crash. This one seems to be mostly consistent; see below and new attached code.

    If you're going to tell me that Tkinter simply can never be called by any thread other than the one animating mainloop - in other words, Tkinter calls are only safe within Tkinter callbacks like a Button's command function - then please suggest an alternative library that is sturdier. There's nothing I can do about the fact that multiple threads produce independent data that has to go onto a single graph.

    Exception in thread Thread-1:
    Traceback (most recent call last):
      File "C:\Python27\lib\threading.py", line 530, in __bootstrap_inner
        self.run()
      File "C:\Documents and Settings\mayos\Desktop\PMT2\MyProjects\TkinterCrash.py", line 68, in run
        self.graph.create_line(element[0], element[1], element[2], element[3])
      File "C:\Python27\lib\lib-tk\Tkinter.py", line 2201, in create_line
        return self._create('line', args, kw)
      File "C:\Python27\lib\lib-tk\Tkinter.py", line 2189, in _create
        *(args + self._options(cnf, kw))))
    ValueError: invalid literal for int() with base 10: 'None'

    But once I got:

    Exception in thread Thread-1:
    Traceback (most recent call last):
      File "C:\Python27\lib\threading.py", line 530, in __bootstrap_inner
        self.run()
      File "C:\Documents and Settings\mayos\Desktop\PMT2\MyProjects\TkinterCrash2.py", line 68, in run
        self.graph.create_line(element[0], element[1], element[2], element[3])
      File "C:\Python27\lib\lib-tk\Tkinter.py", line 2201, in create_line
        return self._create('line', args, kw)
      File "C:\Python27\lib\lib-tk\Tkinter.py", line 2189, in _create
        *(args + self._options(cnf, kw))))
    TclError: can not find channel named "Nonefile13cad48"

    @PythonInTheGrass
    Copy link
    Mannequin Author

    PythonInTheGrass mannequin commented Jan 28, 2011

    Alright. More digging turned up the Tkinter "after" function, aka WM_TIMER for Windowy people like me, and that plus a nonblocking queue get() gets all my drawing operations back into the mainLoop() thread. Voilà, no more crashes.

    Let me suggest that page one, sentence one of any Tkinter documentation should begin "Tkinter is not thread safe", with a link to an example of after() and nonblocking get(). I've changed the component to Documentation. This would save a few days for poor sods like me -- I'm used to low level Windows C++ GUI work, where any thread can call any SDK function at any time, and Windows sorts it all out.

    Having to force everything into a single thread, and then poll for my data (GAG), is something I thought died in the 80's. Is anyone looking at thread safe GUI libraries?

    @PythonInTheGrass PythonInTheGrass mannequin added docs Documentation in the Doc dir and removed topic-tkinter labels Jan 28, 2011
    @terryjreedy
    Copy link
    Member

    There are other gui libraries with Python interfaces that you can look at. I agree that something in doc about how to feed data from multiple threads would be nice.

    @terryjreedy terryjreedy added type-bug An unexpected behavior, bug, or error and removed type-crash A hard crash of the interpreter, possibly with a core dump labels Jan 28, 2011
    @terryjreedy
    Copy link
    Member

    I have somewhat arbitrary selected bpo-16823 as the issue turned into a tkinter and threads doc issue. I added a note there about mentioning the use of queue.

    @Jackmoo
    Copy link
    Mannequin

    Jackmoo mannequin commented May 24, 2015

    Hi there, recently I also encounter this in windows(7), and my python program occasionally crash and the windows pops 'appcrash' message with tcl8.5.dll error c000005 (access violation).

    And this end up related to thread safe problem described as above. Since in my program, I have to build the tkinter UI in another thread (main thread was occupied by other module which blocking), so I can't follow the 'build UI in main thread' solution. My work around is, add a handler which using .after() and get_nowait() to call itself periodically to handle the command in queue.

    def commandQueueHandler(self):
        try:
            while 1:
                your_command = self.textCommandQueue.get_nowait()
                if your_command is not None:
                    # execute the command ....
                self.Text.update_idletasks()
        except Queue.Empty:
            pass
        self.Text.after(100, self.commandQueueHandler)

    Once this method is triggered, just build another thread to put() command in textCommandQueue, then it will be executed periodically.
    One thing that should mention is the update_idletasks() should be added after each command execution, otherwise the UI refresh will be slower then expected. (in my case, the scrolling of Text widge is a bit 'sticky' when I pull it. After adding update_idletasks(), it becomes smoother.)

    TL:DR,
    If you have to run tkinter UI in another thread, add a queue and self-called method with after() and get_nowait() in UI thread to handle the queue. If you want to send command to UI at other thread, just put() the command in the queue of UI thread.

    @terryjreedy
    Copy link
    Member

    Thanks for the report.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    docs Documentation in the Doc dir type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    1 participant