Thursday, March 31, 2011

python exit a blocking thread?

in my code i loop though raw_input() to see if the user has requested to quit. My app can quit before the user quits, but my problem is the app is still alive until i enter a key to return from the blocking function raw_input(). Can i do to force raw_input() to return? by maybe sending it fake input? could i terminate the thread its on? (the only data it has is a single var call wantQuit).

From stackoverflow
  • You might use a non-blocking function to read user input.
    This solution is windows-specific:

    import msvcrt
    import time
    
    while True:
        # test if there are keypresses in the input buffer
        while msvcrt.kbhit(): 
            # read a character
            print msvcrt.getch()
        # no keypresses, sleep for a while...
        time.sleep(1)
    

    To do something similar in Unix, which reads a line at a time, unlike the windows version reading char by char (thanks to Aaron Digulla for providing the link to the python user forum):

    import sys
    import select
    
    i = 0
    while i < 10:
        i = i + 1
        r,w,x = select.select([sys.stdin.fileno()],[],[],2)
        if len(r) != 0:
            print sys.stdin.readline()
    

    See also: http://code.activestate.com/recipes/134892/

    Aaron Digulla : +1 for taking the time to write an example :)
  • You can use this time out function that wraps your function. Here's the recipe from: http://code.activestate.com/recipes/473878/

    def timeout(func, args=(), kwargs={}, timeout_duration=1, default=None):
        '''This function will spwan a thread and run the given function using the args, kwargs and 
        return the given default value if the timeout_duration is exceeded 
        ''' 
        import threading
        class InterruptableThread(threading.Thread):
            def __init__(self):
                threading.Thread.__init__(self)
                self.result = default
            def run(self):
                try:
                    self.result = func(*args, **kwargs)
                except:
                    self.result = default
        it = InterruptableThread()
        it.start()
        it.join(timeout_duration)
        if it.isAlive():
            return it.result
        else:
            return it.result
    
    Deestan : Nice. Confirmed to work in both WinXP and Linux.
  • There is a post on the Python mailing list which explains how to do this for Unix:

    # this works on some platforms:
    
    import signal, sys
    
    def alarm_handler(*args):
        raise Exception("timeout")
    
    def function_xyz(prompt, timeout):
        signal.signal(signal.SIGALRM, alarm_handler)
        signal.alarm(timeout)
        sys.stdout.write(prompt)
        sys.stdout.flush()
        try:
            text = sys.stdin.readline()
        except:
            text = ""
        signal.alarm(0)
        return text
    
    Paolo Tedesco : Thanks, I added a small example in my answer based on that post (+1)
    jonasl : 404 on the link
    Aaron Digulla : Thanks. Fixed the link and copied the source here.
  • Why don't you just mark the thread as daemonic?

    From the docs:

    A thread can be flagged as a “daemon thread”. The significance of this flag is that the entire Python program exits when only daemon threads are left. The initial value is inherited from the creating thread. The flag can be set through the daemon attribute.

0 comments:

Post a Comment