The operating system's signals are the interruptions it sends to processes, and they have the power to end a program early. On a UNIX, LINUX, Mac OS X, or Windows system, pressing Ctrl+C will cause an interruption. The interrupts known as signals are the ones that compel an OS to pause its current task in order to attend to the one for which the interrupt was sent. Any OS software can experience a service pause due to these interrupts. In a similar vein, C++ provides a variety of signals that can be processed by programs.
A signal handler is simply a function that is compiled along with all the rest of the program. You can instruct the operating system to call a function when a signal is received without explicitly calling it by using signal or sigaction.
The user of C++ can deal with the following list of numerous signals and their operations.
Signals | Operations |
---|---|
SIGINT
|
creates a receipt for a signal that is active |
SIGTERM
|
a request to terminate the program is sent. |
SIGBUS
|
Access to an incorrect address was indicated by a bus error. |
SIGILL |
finds a command that is not permitted
|
SIGALRM
|
This serves as a reminder that the timer is about to expire and is used by the alarm() function. |
SIGABRT |
program termination that occurs unexpectedly |
SIGSTOP
|
The signal has the potential to halt a process and cannot be prevented, handled, or ignored. |
SIGSEGV
|
invalid storage access |
SIGFPE
|
Operations that overflow or are mathematically improper, such as dividing by zero. |
SIGUSR1
|
These are User-Defined Signals |
SIGSUR2
|
These are User-Defined Signals |
The signal function in the C++ signal-handling package can be used to capture unforeseen interruptions or events. That means the signal library's signal() function is available and is used to capture unwanted interruptions or events.
Syntax
signal(registered signal, signal handler)
void (*signal (int sig, void (*func)(int)))(int);
Here the first argument is an integer that denotes the signal number, and the second argument is a pointer to a function that handles the signals. We need to keep in mind that the signal we want to capture needs to be registered using a signal function and connected to a signal processing function. The signal processing function needs to be of type void.
#include <csignal>
#include <iostream>
using namespace std;
void signal_handler(int signal_num)
{
cout << "The interrupt signal is (" << signal_num
<< "). \n";
// It will terminates the program
exit(signal_num);
}
int main()
{
// register the signal SIGABRT as well as signal handler
signal(SIGABRT, signal_handler);
while (true)
cout << "Hai and Hello learnEtutorials..." << endl;
return 0;
}
Output:
Hai and Hello learnEtutorials... Hai and Hello learnEtutorials... Hai and Hello learnEtutorials... Hai and Hello learnEtutorials...
Output: Because this code is in an infinite loop, it will display the above output until an interrupt occurs:
Now, if we use Ctrl+C to transmit an interrupt, the program will end by printing the following message:
Output:
Hai and Hello learnEtutorials... Hai and Hello learnEtutorials... Hai and Hello learnEtutorials... Hai and Hello learnEtutorials... The interrupt signal is (22).
#include <iostream>
#include <csignal>
using namespace std;
sig_atomic_t signalled = 0;
void handler(int sig)
{
signalled = 1;
}
int main()
{
signal(SIGINT, handler);
raise(SIGINT);
if (signalled)
cout << "The Signal is handled";
else
cout << "The Signal is not handled";
return 0;
}
Output:
The Signal is handled
Sending signals to the currently running application requires the usage of the C++ signal raise()
function. The function raise() was designated in the <csignal>
header file to handle a specific signal.
Syntax
int raise (int sig);
Parameters
sig: The signal that needs to be transmitted for processing. It can have the following values:
Return value
It returns zero upon success and a non-zero upon failure.
Data Races
This function can be called simultaneously without triggering any data races.
Exceptions
When a signal is raised and no function handlers have been assigned to handle it, this function never throws an exception.
For example 1
In order to demonstrate the use of the raise() function whenever SIGABRT is passed, let's look at a straightforward example:
#include <iostream>
#include <csignal>
using namespace std;
sig_atomic_t sig_value = 0;
void handler(int sig)
{
sig_value = sig;
}
int main()
{
signal(SIGABRT, handler);
cout << "Before the signal handler is called" << endl;
cout << "Signal = " << sig_value << endl;
raise(SIGABRT);
cout << "After the signal handler is called" << endl;
cout << "Signal = " << sig_value << endl;
return 0;
}
Output:
Before the signal handler is called Signal = 0 After the signal handler is called Signal = 6
For example 2
To demonstrate the use of the raise() function whenever the SIGINT is provided, let's look at a straightforward example:
#include <csignal>
#include <iostream>
using namespace std;
sig_atomic_t s_value = 0;
void handle(int signal_)
{
s_value = signal_;
}
int main()
{
signal(SIGINT, handle);
cout << "Before the called Signal = " << s_value << endl;
raise(SIGINT);
cout << "After the called Signal = " << s_value << endl;
return 0;
}
Output:
Before the called Signal = 0 After the called Signal = 2
For example 3
As an example of how to use the raise() function when SIGTERM is supplied, let's look at a straightforward example:
#include <csignal>
#include <iostream>
using namespace std;
sig_atomic_t s_value = 0;
void handle(int signal_)
{
s_value = signal_;
}
int main()
{
signal(SIGTERM, handle);
cout << "Before the called Signal = " << s_value << endl;
raise(SIGTERM);
cout << "After the called Signal = " << s_value << endl;
return 0;
}
Output:
Before the called Signal = 0 After the called Signal = 15