7

I've slightly modified the signal example from the official docs (bottom of page).

I'm calling sleep 10 but I would like an alarm to be raised after 1 second. When I run the following snippet it takes way more than 1 second to trigger the exception (I think it runs the full 10 seconds).

import signal, os

def handler(signum, frame):
    print 'Interrupted', signum
    raise IOError("Should after 1 second")

signal.signal(signal.SIGALRM, handler)
signal.alarm(1)

os.system('sleep 10')

signal.alarm(0)

How can I be sure to terminate a function after a timeout in a single-threaded application?

Juicy
  • 11,840
  • 35
  • 123
  • 212
  • Doesn't your call to the system `sleep` suspend everything, including the signal timer? The alarm doesn't go off because it's asleep too. You probably have to push that `sleep` call into a separate process with the [`subprocess`](https://docs.python.org/3/library/subprocess.html) module. – JCVanHamme Jan 19 '16 at 14:38

1 Answers1

7

From the docs:

A Python signal handler does not get executed inside the low-level (C) signal handler. Instead, the low-level signal handler sets a flag which tells the virtual machine to execute the corresponding Python signal handler at a later point(for example at the next bytecode instruction).

Therefore, a signal such as that generated by signal.alarm() can't terminate a function after a timeout in some cases. Either the function should cooperate by allowing other Python code to run (e.g., by calling PyErr_CheckSignals() periodically in C code) or you should use a separate process, to terminate the function in time.

Your case can be fixed if you use subprocess.check_call('sleep 10'.split()) instead of os.system('sleep 10').

0 _
  • 10,524
  • 11
  • 77
  • 109
jfs
  • 399,953
  • 195
  • 994
  • 1,670