How to Capture Sigint in Python

How do I capture SIGINT in Python?

Register your handler with signal.signal like this:

#!/usr/bin/env python
import signal
import sys

def signal_handler(sig, frame):
print('You pressed Ctrl+C!')
sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')
signal.pause()

Code adapted from here.

More documentation on signal can be found here.
 

python: catch SIGINT in process reading data from a socket

Looks like your internal loop is blocking progBreak check, this code is working for me:

import signal

progBreak = False

def newBreakHandler(signum, frame):
global progBreak
progBreak = True


def runMain():
global progBreak

signal.signal(signal.SIGINT, newBreakHandler)


while not progBreak:
while not progBreak and client.poll():
command = client.recv_bytes()

print "Exiting..."

runMain()

Catch SIGINT and call a method in an object

I'm not sure why you added the part

When I try to add another argument to sigint_handler, I get an error.

to your Question, but i'll first cover that:

use a wrapper or partial (which is a wrapper-factory) like so:

>>> def my_wrapped_sigint_handler(my_argument):
... def signal_handler(signum, frame): # the actual sigint handler
... print(my_argument) # or do something useful
... return signal_handler
...
>>> signal.signal(signal.SIGINT, my_wrapped_sigint_handler('FOO'))

or using partial:

>>> from functools import partial
>>> def sigint_handler(signum, frame, my_argument):
... print(my_argument) # or do something useful
...
>>> signal.signal(signal.SIGINT, partial(sigint_handler, my_argument="foobar"))

to adress your original question using the technique above:

>>> class MyObject:
... def terminate (self):
... do_something()
...
>>> def sigint_handler(signum, frame, obj):
... obj.terminate()
...
>>> signal.signal(signal.SIGINT, partial(sigint_handler, obj=MyObject()))

will call MyObject's instance's .terminate() on ^C.

How do I capture SIGINT in Python on Windows?

After opening the bug upstream the root cause of the problem was found and a patch was written. This patch won't be going into the python 2.x series.

Catch Ctrl+C / SIGINT and exit multiprocesses gracefully in python

The previously accepted solution has race conditions and it does not work with map and async functions.


The correct way to handle Ctrl+C/SIGINT with multiprocessing.Pool is to:

  1. Make the process ignore SIGINT before a process Pool is created. This way created child processes inherit SIGINT handler.
  2. Restore the original SIGINT handler in the parent process after a Pool has been created.
  3. Use map_async and apply_async instead of blocking map and apply.
  4. Wait on the results with timeout because the default blocking waits to ignore all signals. This is Python bug https://bugs.python.org/issue8296.

Putting it together:

#!/bin/env python
from __future__ import print_function

import multiprocessing
import os
import signal
import time

def run_worker(delay):
print("In a worker process", os.getpid())
time.sleep(delay)

def main():
print("Initializng 2 workers")
original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
pool = multiprocessing.Pool(2)
signal.signal(signal.SIGINT, original_sigint_handler)
try:
print("Starting 2 jobs of 5 seconds each")
res = pool.map_async(run_worker, [5, 5])
print("Waiting for results")
res.get(60) # Without the timeout this blocking call ignores all signals.
except KeyboardInterrupt:
print("Caught KeyboardInterrupt, terminating workers")
pool.terminate()
else:
print("Normal termination")
pool.close()
pool.join()

if __name__ == "__main__":
main()

As @YakovShklarov noted, there is a window of time between ignoring the signal and unignoring it in the parent process, during which the signal can be lost. Using pthread_sigmask instead to temporarily block the delivery of the signal in the parent process would prevent the signal from being lost, however, it is not available in Python-2.



Related Topics



Leave a reply



Submit