views:

77

answers:

1

Hello,

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.

+1  A: 

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()
pyInTheSky
I don't fully understand what the first answerer was doing with this UDP client/server. PyDev doesn't work because it gets these weird errors with some XML file that the debugger tries to write to with state information. Maybe it has multiple threads trying to write to the file at the same time when running a multithreaded program, and isn't set up to handle that.
MMM
sorry, never used pyDev
pyInTheSky