Re: [Tkinter-discuss] Proposal for thread-safe Tkinter
On Thu, Oct 23, 2008 at 5:49 PM, Allen Taylor <Allen.Taylor@mdacorporation.com> wrote:
I was given the task of upgrading a Python/Tkinter GUI application to the latest versions of Python and Tk. After a while, I realized that the application had not been written in a thread-safe manner. Multiple threads would simply use the Tk object directly. The application apparently ran fine (i.e., didn't crash!) using older versions of Python (2.2) and Tk (8.3), but it started to have serious problems (i.e., crashing) after using the latest versions.
Did you compile these new tcl/tk versions with --enable-threads ? That is where the problem lies in _tkinter currently. In a tk.call it checks if python was compiled with threads, but if tcl wasn't compiled with threads support too, _tkinter acts like single threaded and then you get these crashes (this happens in other places there too).
The problem is that there isn't enough budget to fix the whole application. So, I invested a bit of time to develop mtTkinter, a thread-safe version of Tkinter. Importing mtTkinter actually modifies the original Tkinter in such a way to make it thread-safe, recognizing and diverting out-of-thread calls to the Tk object creation thread via a queue and an 'after' event. I think it works quite well, requiring basically no changes to the application other than to import mtTkinter instead of (or in addition to) Tkinter. Even packages that use Tkinter (e.g., Pmw) benefit.
I would like to contribute this module (single file, about 160 lines) to the Python community, but I don't know how. I'm new to Python and am not initiated in the deep Pythonic developer world. Can someone give me some pointers? Many thanks.
I have read your other email where you posted the code for this module but let me comment on it here too. It is nice that it fixes the problem mentioned above ;) And I believe _tkinter deserves a fix in this respect, I don't think it was intended to not work correctly when python has thread support and tcl/tk doesn't.
Allen B. Taylor MDA 9445 Airport Road Brampton, ON L6S 4J3 905-790-2800 ext. 4350 allen.taylor@mdacorporation.com -- http://mail.python.org/mailman/listinfo/python-list
-- -- Guilherme H. Polo Goncalves
Hi Guilherme, The versions of Python and Tk used are the default packages installed on Linux (Ubuntu 6.06 LTS). I don't know whether the default install is compiled with --enable-threads or not. So, mtTkinter seems to be handy if you want to use the default installed packages? Allen
"Guilherme Polo" <ggpolo@gmail.com> 2008-10-24 15:00 >>> On Thu, Oct 23, 2008 at 5:49 PM, Allen Taylor <Allen.Taylor@mdacorporation.com> wrote: I was given the task of upgrading a Python/Tkinter GUI application to the latest versions of Python and Tk. After a while, I realized that the application had not been written in a thread-safe manner. Multiple threads would simply use the Tk object directly. The application apparently ran fine (i.e., didn't crash!) using older versions of Python (2.2) and Tk (8.3), but it started to have serious problems (i.e., crashing) after using the latest versions.
Did you compile these new tcl/tk versions with --enable-threads ? That is where the problem lies in _tkinter currently. In a tk.call it checks if python was compiled with threads, but if tcl wasn't compiled with threads support too, _tkinter acts like single threaded and then you get these crashes (this happens in other places there too).
The problem is that there isn't enough budget to fix the whole application. So, I invested a bit of time to develop mtTkinter, a thread-safe version of Tkinter. Importing mtTkinter actually modifies the original Tkinter in such a way to make it thread-safe, recognizing and diverting out-of-thread calls to the Tk object creation thread via a queue and an 'after' event. I think it works quite well, requiring basically no changes to the application other than to import mtTkinter instead of (or in addition to) Tkinter. Even packages that use Tkinter (e.g., Pmw) benefit.
I would like to contribute this module (single file, about 160 lines) to the Python community, but I don't know how. I'm new to Python and am not initiated in the deep Pythonic developer world. Can someone give me some pointers? Many thanks.
I have read your other email where you posted the code for this module but let me comment on it here too. It is nice that it fixes the problem mentioned above ;) And I believe _tkinter deserves a fix in this respect, I don't think it was intended to not work correctly when python has thread support and tcl/tk doesn't.
Allen B. Taylor MDA 9445 Airport Road Brampton, ON L6S 4J3 905-790-2800 ext. 4350 allen.taylor@mdacorporation.com -- http://mail.python.org/mailman/listinfo/python-list
-- -- Guilherme H. Polo Goncalves
On Fri, Oct 24, 2008 at 5:31 PM, Allen Taylor <Allen.Taylor@mdacorporation.com> wrote:
Hi Guilherme, The versions of Python and Tk used are the default packages installed on Linux (Ubuntu 6.06 LTS). I don't know whether the default install is compiled with --enable-threads or not. So, mtTkinter seems to be handy if you want to use the default installed packages? Allen
To check for --enable-threads try this: import Tkinter Tkinter.Tk().getvar("tcl_platform(threaded)") You will either get 1, or a TclError. Also, I though you said latest tcl/tk versions but clearly tcl/tk packages in Ubuntu 6.06 are not the latest. But they also won't make a difference if you didn't recompile python with these packages, I'm just telling this because right now Ubuntu includes tcl/tk 8.5 but distributes python-tk compiled against tcl/tk 8.4. Maybe you could include one example where this new module makes a difference ? We could be talking about different things. For instance, this: import Tkinter def test(text_widget): text_widget.config(text='abcdef') def try_it(text_widget): threading.Thread(target=test, args=(text_widget, )).start() lbl = Tkinter.Label() lbl.pack() lbl.after(10, lambda: try_it(lbl)) lbl.mainloop() Would crash if tcl/tk were not compiled with --threads-enabled, but then using your module it will run just fine. -- -- Guilherme H. Polo Goncalves
so if you do compile that way, Tk is thread safe, I can have separate mainloops in different threads and they can all post to each others windows, etc? On Fri, 2008-10-24 at 17:45 -0200, Guilherme Polo wrote:
On Fri, Oct 24, 2008 at 5:31 PM, Allen Taylor <Allen.Taylor@mdacorporation.com> wrote:
Hi Guilherme, The versions of Python and Tk used are the default packages installed on Linux (Ubuntu 6.06 LTS). I don't know whether the default install is compiled with --enable-threads or not. So, mtTkinter seems to be handy if you want to use the default installed packages? Allen
To check for --enable-threads try this:
import Tkinter Tkinter.Tk().getvar("tcl_platform(threaded)")
You will either get 1, or a TclError.
Also, I though you said latest tcl/tk versions but clearly tcl/tk packages in Ubuntu 6.06 are not the latest. But they also won't make a difference if you didn't recompile python with these packages, I'm just telling this because right now Ubuntu includes tcl/tk 8.5 but distributes python-tk compiled against tcl/tk 8.4.
Maybe you could include one example where this new module makes a difference ? We could be talking about different things. For instance, this:
import Tkinter
def test(text_widget): text_widget.config(text='abcdef')
def try_it(text_widget): threading.Thread(target=test, args=(text_widget, )).start()
lbl = Tkinter.Label() lbl.pack() lbl.after(10, lambda: try_it(lbl))
lbl.mainloop()
Would crash if tcl/tk were not compiled with --threads-enabled, but then using your module it will run just fine.
On 10/27/08, C. Allen <callen@gemini.edu> wrote:
so if you do compile that way, Tk is thread safe, I can have separate mainloops in different threads and they can all post to each others windows, etc?
No, it doesn't make tk thread safe, it makes tkinter protect access from multiple threads to data in tcl/tk. Also, having multiple mainloops is another story. To have multiple mainloops you would be creating multiple tcl interpreters, which is allowed by tkinter but it will cause all sort of weird errors. Now what you can do when tcl/tk is compiled with --enable-threads and python has thread support too is creating threads in python and changing tk widgets in another thread. tkinter will schedule these calls from other threads to run in the main thread (with a probability to fail). Other toolkits, like qt, require explicit scheduling from the user in these situations, but tkinter tries to do it automatically.
On Fri, 2008-10-24 at 17:45 -0200, Guilherme Polo wrote: On Fri, Oct 24, 2008 at 5:31 PM, Allen Taylor <Allen.Taylor@mdacorporation.com> wrote:
Hi Guilherme, The versions of Python and Tk used are the default packages installed on Linux (Ubuntu 6.06 LTS). I don't know whether the default install is compiled with --enable-threads or not. So, mtTkinter seems to be handy if you want to use the default installed packages? Allen
To check for --enable-threads try this:
import Tkinter Tkinter.Tk().getvar("tcl_platform(threaded)")
You will either get 1, or a TclError.
Also, I though you said latest tcl/tk versions but clearly tcl/tk packages in Ubuntu 6.06 are not the latest. But they also won't make a difference if you didn't recompile python with these packages, I'm just telling this because right now Ubuntu includes tcl/tk 8.5 but distributes python-tk compiled against tcl/tk 8.4.
Maybe you could include one example where this new module makes a difference ? We could be talking about different things. For instance, this:
import Tkinter
def test(text_widget): text_widget.config(text='abcdef')
def try_it(text_widget): threading.Thread(target=test, args=(text_widget, )).start()
lbl = Tkinter.Label() lbl.pack() lbl.after(10, lambda: try_it(lbl))
lbl.mainloop()
Would crash if tcl/tk were not compiled with --threads-enabled, but then using your module it will run just fine.
-- -- Guilherme H. Polo Goncalves
Thanks for the explanation Guilherme. Thanks... I see what you mean technically about it not making tk thread safe, but, it makes tkinter's use of tk from python threadsafe (with the mainloop caveat that it's not meant to be run more than once at any rate). On Mon, 2008-10-27 at 17:57 -0200, Guilherme Polo wrote:
On 10/27/08, C. Allen <callen@gemini.edu> wrote:
so if you do compile that way, Tk is thread safe, I can have separate mainloops in different threads and they can all post to each others windows, etc?
No, it doesn't make tk thread safe, it makes tkinter protect access from multiple threads to data in tcl/tk.
Also, having multiple mainloops is another story. To have multiple mainloops you would be creating multiple tcl interpreters, which is allowed by tkinter but it will cause all sort of weird errors.
Now what you can do when tcl/tk is compiled with --enable-threads and python has thread support too is creating threads in python and changing tk widgets in another thread. tkinter will schedule these calls from other threads to run in the main thread (with a probability to fail).
Other toolkits, like qt, require explicit scheduling from the user in these situations, but tkinter tries to do it automatically.
On Fri, 2008-10-24 at 17:45 -0200, Guilherme Polo wrote: On Fri, Oct 24, 2008 at 5:31 PM, Allen Taylor <Allen.Taylor@mdacorporation.com> wrote:
Hi Guilherme, The versions of Python and Tk used are the default packages installed on Linux (Ubuntu 6.06 LTS). I don't know whether the default install is compiled with --enable-threads or not. So, mtTkinter seems to be handy if you want to use the default installed packages? Allen
To check for --enable-threads try this:
import Tkinter Tkinter.Tk().getvar("tcl_platform(threaded)")
You will either get 1, or a TclError.
Also, I though you said latest tcl/tk versions but clearly tcl/tk packages in Ubuntu 6.06 are not the latest. But they also won't make a difference if you didn't recompile python with these packages, I'm just telling this because right now Ubuntu includes tcl/tk 8.5 but distributes python-tk compiled against tcl/tk 8.4.
Maybe you could include one example where this new module makes a difference ? We could be talking about different things. For instance, this:
import Tkinter
def test(text_widget): text_widget.config(text='abcdef')
def try_it(text_widget): threading.Thread(target=test, args=(text_widget, )).start()
lbl = Tkinter.Label() lbl.pack() lbl.after(10, lambda: try_it(lbl))
lbl.mainloop()
Would crash if tcl/tk were not compiled with --threads-enabled, but then using your module it will run just fine.
participants (3)
-
Allen Taylor -
C. Allen -
Guilherme Polo