5

Since tkinter isn't thread-safe, I often see people use the after method to queue some code for execution in the main thread. Here's an example:

import tkinter as tk
from threading import Thread

def change_title():
    root.after(0, root.title, 'foo')

root = tk.Tk()
Thread(name='worker', target=change_title).start()
root.mainloop()

So instead of executing root.title('foo') directly in the worker thread, we queue it with root.after and let the main thread execute it. But isn't calling root.after just as bad as calling root.title? Is root.after thread-safe?

Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
  • I guess root.after adds a task in a queue, from which the tasks are executed sequentially by root.mainloop() – Lev Leontev Sep 26 '19 at 14:18
  • Well `after()` is simply tkinter's way of managing events to be run after a specific time. It is no different than just calling the function/command directly but simply done at a later time. I do not believe it has any interaction with the threaded task it is calling. I don't work with the global namespace from within a thread like this though so I am not sure. I typically pass anything that needs to be updated to the thread and then make changes from there. – Mike - SMT Sep 26 '19 at 14:46
  • 1
    If ***"Since tkinter isn't thread-safe!"*** is `True` then ***"Is root.after thread-safe?"*** can't be `True`? – stovfl Sep 26 '19 at 14:55
  • @Mike-SMT I don't think this is true: _"It is no different than just calling the function/command directly but simply done at a later time. "_. It's a significant difference, in that calling `after` simply adds something to a queue, it doesn't touch the internal widget objects. – Bryan Oakley Sep 26 '19 at 17:26
  • Have you read the following answer? It is probably the most authoritative answer on threading, given that it was written by one of the Tcl developers: https://stackoverflow.com/a/38767665/7432 – Bryan Oakley Sep 26 '19 at 17:40
  • @BryanOakley I hadn't seen that, thanks. Sounds like a "no" to me. – Aran-Fey Sep 26 '19 at 17:43
  • @BryanOakley That makes sense. So by assigning an event to occur say to `root` then does that mean the event is actually occurring in the main thread and has no issues from being assigned during a threaded function? – Mike - SMT Sep 26 '19 at 17:50
  • @Mike-SMT: Assuming that mainloop pulls the item off of the queue, it will be run in whatever thread `mainloop` is running in -- which is presumably the main thread. However, if you call `update` from some other thread, it will probably be run in that thread. – Bryan Oakley Sep 26 '19 at 17:52
  • @BryanOakley oh ok good to know. If you run `update()` from another thread that sounds like it could cause some issues. – Mike - SMT Sep 26 '19 at 17:53

1 Answers1

1

after is thread-safe because it is implemented in terms of call which is generally thread-safe according to the CPython source code if CPython and Tcl were built with thread support (the most common case). This means quite a large footprint of tkinter methods are thread-safe, but not all (particularly eval).

If you call after (or call) from some other CPython thread, it will actually send a thread-safe message to the main thread (with the Tcl interpreter) to actually interact with the Tcl API and run the command in the main thread.