1

I am trying to implement a function that will timeout if it fails to complete in a certain amount of time (having issues with a thread hanging). This answer seemed the most promising, effectively providing an API wrapper with which to call my actual function. It generally seems to work (see loop_forever), but fails to stop when I use time.sleep. Why does the timeout not work with the sleep timer and will this work as a way to prevent threads from hanging?

import signal
import time

def timeout(func, args=(), kwargs={}, timeout_duration=1, default=None):


    class TimeoutError(Exception):
        pass

    def handler(signum, frame):
        raise TimeoutError()

    # set the timeout handler
    signal.signal(signal.SIGALRM, handler) 
    signal.alarm(timeout_duration)
    try:
        result = func(*args, **kwargs)
    except TimeoutError as exc:
        result = default
    finally:
        signal.alarm(0)

    return result




def loop_forever():
    x = 0
    while True:
        print x
        try:
            x += 1
        except:
            continue

def loop_forever_sleep():
    x = 0
    while True:
        print x
        try:
            x += 1
            time.sleep(10)
        except:
            continue

if __name__ == '__main__':
    a = timeout(loop_forever) #Terminates
    b = timeout(loop_forever_sleep) #Does not terminate
2
  • What platforms are you targeting? Commented Oct 29, 2014 at 17:50
  • This is on Linux, I understand this function will not work on Windows. Commented Oct 29, 2014 at 18:00

1 Answer 1

1

The problem is that the SIGALRM is being raised while you're inside of the time.sleep(10) system call, which causes your handler to be called in that context, too. However, you're swallowing all the exceptions that happen inside of your infinite loop, so the TimeoutError never makes it back to the timeout function, instead it gets ignored by the except: continue code inside of loop_forever_sleep. Just remove the try/except block from the while True loop and it will work fine:

def loop_forever_sleep():
    x = 0
    while True:
        print x
        x += 1
        time.sleep(10)
Sign up to request clarification or add additional context in comments.

2 Comments

So that means that anytime the timout occurs in a try block it will not get back to the API, just end that try block?
@Michael If you use bare except blocks, which will trap the TimeoutError, yes. You'll need to either only catch the specific exceptions you're expecting in your try blocks, or always re-raise TimeoutError if you catch it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.