Signal are a means by which you can communicate with a process (or processes can communicate between each others). The two most popular signals are SIGINT
and SIGTSTP
.
You can send a SIGINT
signal to the process currently running in your terminal with ctrl+c
or cmd+c
. This signal should cause the process to terminate immediately.
You can send a SIGTSTP
signal with ctrl+z
or cmd+z
. This signal will pause the process and give you the prompt back. You can later use the fg
command to send a CONT
signal and resume the process.
By default, python will throw a KeyboardInterrupt
when it receives SIGINT
and will stop executing your script when it receives SIGTSTP
.
The signal module allows to register custom handlers to be executed when a signal is received. If you hold resources that need to be released (e.g. network connections), you can do so through these handlers.
For instance, If your script is a scraper responsible for downloading data from a password-protected website, you will likely want to setup a handler on the CONT
signal to make sure that the connection is established and the session restaured when the script is resumed.
Here's how to register handlers for these three signals (also on github gist):
If you run this script in a terminal, it'll start an infinite loop printing the character "a". Press ctrl+c to send it a sigint signal and exit.
import signal, time, sys, os
import logging
from logging import info
logging.basicConfig(level=logging.INFO, format='\n%(message)s')
def sigint_handler(signum, frame):
info(f'sigint_handler: Received signal {signum} on frame {frame}')
sys.exit(0)
def sigtstp_handler(signum, frame):
info(f'sigtstp_hangler: Received signal {signum} on frame {frame}')
# ... release resource here ...
# Remove our handler
signal.signal(signum, signal.SIG_DFL)
# Resend signal to pause process
os.kill(os.getpid(), signum)
# Back from suspend -- reestablish the handler.
signal.signal(signal.SIGTSTP, sigtstp_handler)
def sigcont_handler(signum, frame):
info(f'sigcont_handler: Received signal {signum} on frame {frame}')
time.sleep(0.5) # acquire resource here ...
info('Ready to go')
# Assign handlers to signals
signal.signal(signal.SIGINT, sigint_handler)
signal.signal(signal.SIGTSTP, sigtstp_handler)
signal.signal(signal.SIGCONT, sigcont_handler)
while True:
for col in range(80):
print('a', end='', flush=True)
time.sleep(0.1)
print()
Read next
This article is part of my complete guide to command-line tools in python.
Previous chapter: How and when to use stdout
and stderr
in python.