Tutorial Study Image

C++ Signal Handling


June 14, 2023, Learn eTutorial
286

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.

What function does a signal handler serve?

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

 

Signal() function

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.

  • Return value: This function's return type and its parameter type, func, are both the same. If the function's request is successful, it provides a pointer to the specific handler function that was in charge of handling this signal prior to the call, if any.
  • Data Races: Data race is not defined. It will result in undefined behavior if you call this function in a multi-threaded program.
  • Exceptions: Never throw an exception in this function.

C++ Program in order to demonstrate the signal() function


#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).

Another example program for signal() function


#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

The raise() Function

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:

  • SIGINT
  • SIGABRT
  • SIGFPE
  • SIGILL
  • SIGSEGV
  • SIGTERM
  • SIGHUP

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:

Example program using SIGABRT


#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:

Example program using SIGINT


#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:

Example program using SIGTERM


#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