I am trying to debug Python using WinPDB and I have multiple threads using threading.Thread. I can never seem to control the threads individually. If I break execution, the entire script breaks. If I step through the source code of one thread, all of the others continue to be interleaved and continue some of their execution. This is true with Synchronicity turned on or off. Isn't there a way to step through a thread individually while keeping the others at a breakpoint?
Is WinPDB the wrong tool to use for this? I just don't know what to use. Eclipse PyDev barely works at all because the debugger itself seems to get race errors when starting multiple threads.
What is a tool that will actually robustly debug a multi-threaded Python program?
Thank you.
Pretty much anything that can be done at the GDB command line can be done with a breakpoint from Python. You can attach commands to a breakpoint, make it conditional, ignore a certain number of hits, make the breakpoint specific to a thread or process, and all of the things you can do from the command line.
I had a similar issue, it's not the most ideal answer, but I'll describe it for you and maybe you can work off of it.
I more or less wrote a mini debugger. Udp Client / Server and a function that did nothing but grab a global lock, sleep .1 seconds, and then release it. This function got passed to each thread. I then put a call to this function between critical areas that i wanted to debug. After starting the program, the udp server would listen for the client, and if i typed "pause", it would grab the same global lock used by the shared function, and not give it up until i typed "play" in the client. So doing this, you can get a fairly tight stop ... depending on the application.
Hope it helps ... Tiny snippet below. My application was for a test platform so what i did was add the function pointer to the base class constructor, and use this instead of time.sleep() .. giving me mild debugability. What you can do is pass this to each thread and add calls to the pause function at the beginning and end of your functions, and it would allow you to break, etc. I removed some of the commands but you can see that this can be made as extensive as you need it.
PAUSE_NOW = thread.allocate_lock()
def pause(s):
'''
FUNCTION: testStatus
DESCRIPTION: function passed to all test objects
INPUTS: none
RETURNS: none
'''
global Pause_NOW
PAUSE_NOW.acquire()
time.sleep(s)
PAUSE_NOW.release()
`
def server():
'''
\r\n
FUNCTION: server
DESCRIPTION: UDP server that launches a UDP client. The client it
starts can issue commands defined in cmdlineop. Most
functions return a status, but some are meant to block
the main thread as a means of pausing a test, in which case
a default response is returned.
INPUTS: none
RETURNS: none
'''
global EXIT
global Pause_NOW
host = "localhost"
port = 21567
buf = 1024
addr = (host,port)
UDPSock = socket(AF_INET,SOCK_DGRAM)
UDPSock.bind(addr)
sleep(1)
os.startfile('client.py')
#os.system('start python client.py')
cmdlineop = {
'pausenow' : "PAUSE_NOW.acquire()",
'playnow' : "PAUSE_NOW.release()",
}
while 1:
output = 'RECEIVED CMD'
# if EXIT: break
data,addr = UDPSock.recvfrom(buf)
if not data:
break
else:
if cmdlineop.has_key(data.split()[0]):
exec(cmdlineop[(data.split()[0])])
UDPSock.sendto(('\n'+output+'\n'),addr)
data = ''
else:
UDPSock.sendto('INVALID CMD',addr)
UDPSock.close()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With