We will learn How to capture and handle operating system signals like SIGINT and SIGBREAK on Linux and Windows OS's (Windows 10,11) to control the flow of your python script during execution.
Contents
- Introduction
- Source codes
- What are Signals
- Checking for available signals in your OS
- Programming Signals on Python 3
- Working of Python SIGINT Signal
- Safely Exiting from an infinite loop in Python
Python OS Signals Video Tutorial
Introduction
We will use the signal module from Python 3 to capture and handle the OS signals.
The tutorial will teach the user to write your own custom signal handler to catch OS signals like
SIGINT (CTRL +C )
SIGBREAK (CTRL+ BREAK)
and How to register the signal with your custom signal handler and override the default signal behavior.
We will then use the SIGINT ,SIGBREAK to exit from an infinite loop in Python while closing our open resources like file objects, database connections, serial connections etc in an orderly manner on Linux and Windows systems.
For Eg
In the below example ,we have an infinite loop constantly doing something in the following manner,
Open SerialPort Connection
Open Database Connection
While 1:
Read from SerialPort
Write that Data to a Database
Now we want to stop our top pseudo script from what it was doing and exit gracefully while closing all the opened resources like Serial port object or File object.
This where we can use the OS signal to interrupt the execution of our infinite loop.
Warning
Some IDE's like Thonny, IDLE etc may interfere with the capture of signals like SIGINT(CTRL+C) or SIGBREAK.
If you are having issues with the signal not triggering your handler function try running the code directly on the command line outside the IDE as shown below (Windows).
D:\> python your_signal_handling_code.py
or on Linux
$python3 your_signal_handling_code.py
Source codes
Website code may be partial or pseudo code just enough to highlight relevant techniques or methods.
Please use the full source codes from our GitHub Repo to avoid errors
What are OS Signals
An Operating System Signal is a way in which a program or process (here our python script) can receive information from the Operating System that certain events like a Keyboard Press (CTRL + C ) or a Fault have happened.
Signals are assigned a Integer Value by the OS.
When we press CTRL + C on our Keyboard the Operating System (Both Windows and Linux) will generate a SIGINT signal that is send to the currently active program .
The receiving Program can either execute the default function specified by the SIGINT signal or It can use a signal handler to trap the SIGINT signal and execute a custom user specified function.
Not all signals are available on all systems. Signals differ between operating systems(Linux/Windows)
Checking for available signals in your OS.
Since not all signals are available in every OS, It is good to know which ones are available on your system.
Here we will be using Python 3 (Python 3.9.x) and to access the OS signals we have to import the signal module
import signal # Import signal module
# available signals on our System
valid_signals = signal.valid_signals() # requires python 3.9.0
# returns a SET
print('Number of Available Signals ->', len(valid_signals) , '\n')
for i in valid_signals:
print(i)
The above partial code will print available signals on a particular OS. Download the full codes from Github
Here
valid_signals = signal.valid_signals()
returns a set of available OS specific signals which are then printed out.
Operating System Signals available on Windows
On running the signal.valid_signals() function from the Python signal module on Windows 10 (below).
We can see that there are 7 Signals as shown below.
On running the signal.valid_signals() function from the Python signal module on Ubuntu Linux System (below).
We can see that there are 62 Signals as shown below.
As you can see from the above images, there are significant differences in the number and types of Signals available in Linux and Windows systems.
Programming OS Signals on Python 3 using Signal Module
To use the Signal received by our script we have to do 2 things
Write a Signal Handler which will do the custom processing ,when Signal is received
Register the Signal with the Signal Handler function
#pseudo python code for demo
import signal
def your_custom_signal_handler(signal_number,frame):
code to do something
code to do something
code to do something
signal.signal(signal.SIGNALNAME,your_custom_signal_handler)
In the above pseudo code,
we first import the Python signal module to access the various functions.
We then create a custom signal handler function that would run when the operating system notifies our Python Script that a signal has been generated. You can name the signal handler function anything you want.
def your_custom_signal_handler(signal_number,frame):
code to do something
then we register the particular signal with our custom signal handling function.
signal.signal(signal.SIGNALNAME,your_custom_signal_handler)
here signal.SIGNALNAME is a place holder and should be replaced by the signal you want to catch.
Eg signal.SIGINT for catching CTRL+C keyboard interrupt.
Eg signal.SIGBREAK for catching CTRL+BREAK keyboard interrupt.
Here we will be using the SIGINT signal to control the execution of our Python 3 script.
SIGINT Signal is common to both Windows and Linux systems and helps us to run our code on both Windows and Linux Systems.
Please use the full code from Github
import signal # Import signal module
#signal handler function
def SignalHandler_SIGINT(SignalNumber,Frame):
print('SignalHandler of signal.SIGINT')
#register the signal with Signal handler
signal.signal(signal.SIGINT,SignalHandler_SIGINT)
#infinite signal from which we have to escape
while 1:
print("Press Ctrl + C ")
time.sleep(1)
Here
def SignalHandler_SIGINT(SignalNumber,Frame):
is the Signal Handling function ,
When the Signal SIGINT is generated this function is called and the print() statement under is called.
The statement
signal.signal(signal.SIGINT,SignalHandler_SIGINT)
registers the signal handler function SignalHandler_SIGINT(SignalNumber,Frame):
with the signal SIGINT (signal.SIGINT)
Working of Python SIGINT Signal handling Code
If you run the above code ,
- The Python script will print "Press CTRL + C" in an infinite loop,
- When you hit CTRL +C on the Keyboard ,
- A SIGINT signal is generated by the OS (Windows/Linux) and send to the executing script.
- The Python script then transfer the control to def SignalHandler_SIGINT(SignalNumber,Frame): and then executes the print statement under it "SignalHandler of signal.SIGINT"
- After which the control will transfer back to the infinite loop
Please note that the code should be run under the command line as IDE's may interfere with the SIGINT signal.
Safely Exiting from an infinite loop in Python using SIGINT signal
In this example we will learn how to safely exit from an infinite loop in Python 3 using the SIGINT (CTRL+C) signal.
In some application like Serial Port Data Acquisition System Software written in Python we have to query a sensor or Microcontroller like Arduino or Raspberry Pi board continuously in a infinite loop.
In those applications we can use the SIGINT signal (CTRL +C) to interrupt the infinite loop and close the application safely without a resource leak.
You can also use a SIGBREAK (CTRL + BREAK ) signal to do so but the signal is only available in Windows while SIGINT is available on both Linux and Windows.
Please use the full code from GitHub
import signal
import time
Sentry = True
# Create a Signal Handler for Signals.SIGINT: CTRL + C
def SignalHandler_SIGINT(SignalNumber,Frame):
global Sentry
Sentry = False
signal.signal(signal.SIGINT,SignalHandler_SIGINT) #regsiter signal with handler
while Sentry: #exit loop when Sentry = False
print('Long continous event Eg,Read from sensor')
time.sleep(1)
print('Out of the while loop')
print('Clean up code Here')
- Now in the above code we are using a Sentry Variable to control the flow of the while loop at the bottom
- The Sentry Variable is set as True, Sentry = True when the script runs first and the while loop runs continuously.
- When the user wants to stop the loop ,he can generate the SIGINT signal by pressing CTRL + C .
- The SIGINT signal handler will run and set the Sentry Variable to False .
- The control then passes to the While loop where Sentry == False will result in loop terminating and control getting passed to print() statements below.
- User can do the cleanup there
Sentry have to defined as Global, inside the signal handler
global Sentry
Sentry = False
Getting out of the infinite loop in Python using SIGINT signal on Windows (below)
Getting out of the infinite loop in Python on Linux using SIGINT signal (below)
This technique is used to build a Python based serial port data acquisition system here
- Log in to post comments