[Python-Dev] Tcl, Tkinter, and threads (original) (raw)
Martin v. L�wis martin@v.loewis.de
12 Dec 2002 19🔞37 +0100
- Previous message: [Python-Dev] Possible low-hanging optimization
- Next message: [Python-Dev] Tcl, Tkinter, and threads
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
I have now applied changes to _tkinter to make it work when Tcl was built with --enable-threads. For those of you interested in such kind of stuff, here is the full story.
This work was triggered by the bug report
where pydoc -g crashes Tcl. It turns out that pydoc uses threads, and invokes a button configure command from a thread different from the one where the Tcl interpreter was called. Tcl uses thread-local storage to associate a TkDisplay* with a X Display*, and that TLS was uninitialized in this other thread.
Discussion with Tcl people at
http://sourceforge.net/tracker/index.php?func=detail&aid=649209&group_id=12997&atid=112997
lead to the conclusion that this is intentional; they call it the "appartment model"; you can use the Tcl interpreter only from the thread that has created it, you cannot pass Tcl_Obj* across thread boundaries, and you cannot invoke Tcl commands from other threads.
If Tcl is not built for threads, this all is not relevant, since there is only a single set of "thread-local" data (i.e. it isn't thread-local); the thread API is still there, anyway.
To overcome this limitation, I now use Tcl Queues to pass commands from one thread the other; this is also how the Tcl thread extension works. You allocate a Tcl_Event, fill some data, put it into a queue, alert the target thread, and block on a Tcl_Condition. The target thread fetches the event from the queue, invokes the callback function, which performs the Tcl action, and notifies the condition.
Passing of results happens to stack variables in the calling thread whose addresses are put into the event.
This kind of marshalling now happens for the following APIs:
- call: passes the PyObject* args to the target thread. There it is converted into Tcl objects, the command is invoked, and the result is converted back to a Python object.
- getvar/setvar/unsetvar: pass the variable name and value, and invoke the Tcl API in the target thread.
- createcommand/deletecommand: likewise.
For a few APIs, this marshalling is not possible in principle:
- mainloop/doonevent: event processing must happen in the interpreter thread, by nature of the Tcl threading model
For a larger number of APIs, I found the effort not worthwhile:
- globalcall, eval, globaleval, evalfile, record, adderrorinfo, exprstring, exprlong, exprdouble, exprboolean, createfilehandler, deletefilehandler
For all these functions, _tkinter will now raise an exception if they are invoked in the wrong thread.
A tricky question is what happens if the target thread is not processing events right now, either because it mainloop hasn't been invoked, or because it is busy doing something else. The current code raises an exception if the target interpreter is not in the mainloop, and blocks (potentially indefinitely) if the target process does not unqueue its events.
This might cause problems if you create multiple interpreters in one thread: it would be sufficient if one of them processes events. Currently, calls to the other interpreters will raise the exception that the mainloop has not been entered. I hope this won't cause problems in practice, since you rarely have more than one interpreter.
With these changes, it would now be possible to build Tcl in threaded mode on Windows. This has both advantages and disadvantages:
- It allows to get rid of the Tcl lock, and the nearly-busy wait.
- It may cause problems for existing applications if they run into one of the limitations. Of course, those applications will run into the same limitations on Unix if Tcl was build with threads enabled.
If Tcl wasn't build with threads enabled, behaviour is nearly unmodified. Python will still invoke the Tcl thread API, but that won't do anything, so there should be no user-visible change.
Regards, Martin
- Previous message: [Python-Dev] Possible low-hanging optimization
- Next message: [Python-Dev] Tcl, Tkinter, and threads
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]