[Pythonmac-SIG] Python threading.Thread vs PyObjC performOnMainThread

gandreas@gandreas.com gandreas at gandreas.com
Mon May 16 20:01:22 CEST 2005


On May 16, 2005, at 11:59 AM, Bob Ippolito wrote:

>
> On May 16, 2005, at 12:35 PM, gandreas at gandreas.com wrote:
>
>
>> So I'm reworking how debugging is handled in PyOXIDE and I've come  
>> to a problem (several, but this is the biggy for the morning).
>>
>> My goal is to separate interacting with the (remote) debugged  
>> client in a separate thread, which forwards messages to the main  
>> thread as needed to run the debugger UI (since all UI must be done  
>> on the main thread).
>>
> ---
>
>> When the user says "debug", we launch the separate processes,  
>> which includes a stub to open up a TCP connection back to the IDE,  
>> which we use to interact with on the main event loop (which was  
>> ugly, since it would then nest, well, it was ugly).  So now I call  
>> the above "spawnRemoteDebugger", it talks with the targeted  
>> process, and then at some point that process says "hey, let's  
>> start debugging" (and transfers over a proxy object to allow the  
>> IDE to interact with something that looks like a pdb object).   
>> That's all more or less fine.
>>
>
> I don't understand why you need to use threads from the host app.   
> The best way I've found to do this is:
>
> Host app (debugger/interpreter UI) uses async TCP interleaved with  
> the main runloop (i.e. NSFileHandle, or something else)
> Debugged app (application or interpreter) uses sync TCP that blocks  
> waiting for interaction from the debugger
>

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.

> 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.

>
>> The problem is that we then allocate and init the debugger  
>> controller (PyDebuggerController).  Since that needs to be done on  
>> the main thread, we use performSelectorOnMainThread.  That works  
>> fine except that when this debugger controller object gets  
>> created, it eventually wants to call the python code associated  
>> said object.  Of course, since that's on the main thread (and not  
>> this other debugger handler thread) it calls  
>> PyThread_aquire_lock.  But the lock is stuck in the thread that  
>> executing the performSelectorOnMainThread line, and everything  
>> just stops (the main thread waits on the semaphore which will  
>> never be released).
>>
>> So, it appears that performSelectorOnMainThread needs some way to  
>> release the lock to let Python code in the main thread be  
>> executed.  Any suggestions for workarounds?
>>
>
> 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...

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...

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