18

I have a function that occasionally hangs.

Normally I would set an alarm, but I'm in Windows and it's unavailable.

Is there a simple way around this, or should I just create a thread that calls time.sleep()?

wim
  • 266,989
  • 79
  • 484
  • 630
eduffy
  • 35,646
  • 11
  • 90
  • 90
  • 3
    Could you please remove the answer from your *question* and post it as an... actual *answer*? – ThiefMaster Jan 23 '15 at 07:49
  • 1
    you could [use `threading.Timer()` instead](http://stackoverflow.com/a/28081214/4279) – jfs Jan 23 '15 at 15:01
  • @LondonRob: Undone! If the OP wants to add the solution they chose to their own question rather than posting it as a separate answer, that's their prerogative (and might save others some time). – martineau Oct 11 '17 at 16:02
  • 1
    @martineau OK, that seems fair enough. I added [the answer](https://stackoverflow.com/a/31671095/2071807) as a community wiki so I didn't get accused of rep-stealing. (BTW: does ThiefMaster's opinion (admin, rep=211k) not at least balance with yours? Or is there more to this than meets the eye?) – LondonRob Oct 11 '17 at 16:52
  • 1
    @LondonRob: Yes, I saw your "answer" and noted the fact it's marked "community wiki". I can only assume if ThiefMaster felt strongly about it, they would have done what you did themselves (so at best you're second guessing them). That's the balance of things. – martineau Oct 11 '17 at 17:52

4 Answers4

3

Here's how the original poster solved his own problem:

Ended up going with a thread. Only trick was using os._exit instead of sys.exit

import os
import time
import threading

class Alarm (threading.Thread):
    def __init__ (self, timeout):
        threading.Thread.__init__ (self)
        self.timeout = timeout
        self.setDaemon (True)
    def run (self):
        time.sleep (self.timeout)
        os._exit (1)

alarm = Alarm (4)
alarm.start ()
time.sleep (2)
del alarm
print 'yup'

alarm = Alarm (4)
alarm.start ()
time.sleep (8)
del alarm
print 'nope'  # we don't make it this far
LondonRob
  • 53,478
  • 30
  • 110
  • 152
3

The most robust solution is to use a subprocess, then kill that subprocess. Python2.6 adds .kill() to subprocess.Popen().

I don't think your threading approach works as you expect. Deleting your reference to the Thread object won't kill the thread. Instead, you'd need to set an attribute that the thread checks once it wakes up.

Rhamphoryncus
  • 339
  • 1
  • 6
  • can you clarify how to use `.kill()` to deal with a hanging function after a certain amount of time? – Double AA Aug 19 '11 at 17:14
  • Rhamphoryncus: I think your point about deleting the thread reference working or not is somewhat moot in this case. The last thing the `run()` method of the `threading.Thread` subclass does is call `os._exit()`, and even if it didn't, the method would finish and effectively become "killed". At worse the `del alarm`s are unnecessary. – martineau Oct 11 '17 at 16:25
2

You could - as you mentioned - just kick off a new thread that sleeps for that number of seconds.

Or you can use one of Windows' multimedia timers (in Python, that'd be in windll.winmm). I believe timeSetEvent is what you're looking for. Incidentally, I found a piece of code that uses it here.

FreeMemory
  • 8,142
  • 7
  • 32
  • 48
0

I realize this thread has been inactive for some time, but I faced a similar issue and hope that someone else may find this useful as well.

As @jfs mentioned in a useful comment, the standard threading module provides a Timer method that works really well for this (docs). It is just a subclass of threading.Thread, but it makes this very simple and clean. It can also be canceled using the inherited cancel method.

import threading
delay_time = 3   # delay time in seconds
def watchdog():
  print('Watchdog expired. Exiting...')
  os._exit(1)

alarm = threading.Timer(delay_time, watchdog)
alarm.start()
my_potentially_never_ending_call()
alarm.cancel()
Daniel Hill
  • 551
  • 3
  • 11