[Pythonmac-SIG] Python threading.Thread vs PyObjC performOnMainThread
gandreas@gandreas.com
gandreas at gandreas.com
Mon May 16 20:53:21 CEST 2005
On May 16, 2005, at 1:22 PM, Bob Ippolito wrote:
>
> On May 16, 2005, at 2:01 PM, gandreas at gandreas.com wrote:
>>>
>>
>> The debugged app works like that, but the way that the "remote
>> object" interface works is also designed to use sync TCP on the host
>> side. Since it's pure python, I didn't want to start adding in
>> NSFileHandles, and the obvious solution was "just use threads", and
>> the whole "block on reads" model was much cleaner than any sort of
>> polling.
>>
>
> This isn't a very good argument since you're already using plenty
> of Objective-C code in there.
>
My goal was to try to not make it worse... (since part of the goal
was to be able to provide a debugging stub that could be included in
anything that embedded python, regardless if it was PyObjC based or
not - or even Mac OS X based).
> Anyway, there's Twisted, asyncore/medusa, etc. for non-blocking
> Python IO... but NSFileHandle or the like is going to be the
> simplest thing that's going to work.
>
The more I investigate this, the more this seems to be the path of
least resistance...
>
>>> If you need a way to interrupt the debugged app asynchronously
>>> (i.e. ctrl-C in gdb), then set up a signal handler in the debugged
>>> app that installs a trace hook from the debugging bootstrap code
>>> that makes it go into debugging mode and send it a signal from the
>>> host app... but that's not something that's ever very clean in
>>> Python.
>>>
>>
>> I haven't quite figured out a good way to handle that one either, but
>> since the other app is a child, sending a signal should work as good
>> as anything.
>>
>
> There's a "you probably shouldn't use this" function in the C API
> that lets you write an extension module that sends an exception to
> another thread, so in theory you could start a background thread
> that sits on this and waits for a "signal" over TCP or the like
> from the parent and then uses that to break into the main thread.
> Don't do this though, there's a lot of reasons not to.
>
> Alternatively, you could start up a second socket on another thread
> and use it to send a signal to its own pid if it hears from the
> host. This would facilitate true remote debugging.
>
I should be able to directly send the signal from the IDE to the
targeted app (since it's a child of the IDE), and the standard "catch
a unix signal invokes the debugger" action should work (since the
debugger interface on the client talks back to the IDE).
>>>
>>> Update to PyObjC from svn and see if that makes a difference.
>>>
>>
>> Can't do that - the goal is to provide something that, at worse,
>> requires the user to install a given binary package (PyOXIDE is
>> designed to directly call packman if it detects PyObjC not being
>> installed, to make things as transparent as possible). If I require
>> the user to download the latest sources and compile it, that becomes
>> a nightmare. If I compile it myself from "latest beta" and included
>> it with PyOXIDE, that prevents bug fixed releases (since PyOXIDE
>> would be hardcoded to run on the older, buggier, pre-release
>> version).
>>
>> There's already far too much "well, it will all work great, but first
>> you need to download this (and then compile that, and install this
>> third thing)..." in the MacPython world that it makes me cringe (and
>> certainly the choice of versions of Python included with the OS don't
>> make the problem less either). Unfortunately, I can't think up a
>> good way to solve that problem so I just cringe a lot and try to not
>> make anything worse...
>>
>
> Well that's too bad. What you're suggesting will make things much
> worse.
>
> The Python interpreter used by your application should be private
> anyway, so you can and should include PyObjC (probably even Python
> itself) inside your application.
Including an entire "custom" version of Python just seems like a bad
solution to me. It may be the only solution, depending on various
other circumstances, but it seems kind of sad to say "well, OS X
ships with Python.framework, but it can't be used to write a Python
IDE".
> I've said this a ton of times, but the ONLY time you should EVER
> run user Python code from an IDE is from separate processes, unless
> it's simply a plugin for the IDE.
I personally don't agree with this. There are plenty of times when I
just need something to "tinker" with, and the separate process model
doesn't work well because I find the ability to have a semi-
persistent state extremely useful (run the script, examine the
results using an interactive window, manually call some of the
routines, fix a routine and run that source file again, etc... - not
to mention that examining the state of objects within the application
is _much_ faster than having to proxy everything through a socket).
Now if there were a "persistent external" mode, that would be another
story (but that's more a "future feature").
> That said, PyObjC 1.3.5 is just about ready to release anyway.
>
Cool!
> If PyOXIDE itself needs a bug fix from a newer version of PyObjC
> (which in this case, I'm almost 100% positive it does), then you
> should update PyOXIDE with a new version of PyObjC.
>
I'm leaning towards redoing things to avoid the "here be dragons"
areas of the map.
>
>> After a good burrito for lunch, I'm thinking that adding an
>> unlockPythonAndPerformSelectorOnMainThread(andRelockAfterwards)
>> method might be the best way to handle this - at least it's something
>> easy that I can add as part of PyOXIDE...
>>
>
> NO! That is really really horribly bad to do. Working around a
> bug in PyObjC by writing code that will break in correct versions
> of PyObjC is absolutely horrible. You should NEVER release the
> lock unless you own it.
>
Here, then, is probably the heart of the problem - the interactions
between python threads spawned by threading.Thread and the main
(objc) thread and performSelectorOnMainThread are "undefined", and
the more I look at it, the more it appears that using
threading.Thread in a PyObjC app is a bad idea and should probably
just be chalked up as "unsupported and probably won't work". It
appears that I'd need to build something on top of NSThread (in
Objective-C) with explicit thread state handling to get this to work
consistently and correctly.
Glenn Andreas gandreas at gandreas.com
<http://www.gandreas.com/> oh my!
quadrium | build, mutate, evolve | images, textures, backgrounds, art
More information about the Pythonmac-SIG
mailing list