C++ Signal Handling - C++ Programming Tutorial
C++ Course / Miscellaneous / C++ Signal Handling

C++ Signal Handling

BLUF: Mastering C++ Signal Handling is a critical step in becoming a proficient C++ developer. This lesson provides a deep dive into the syntax, performance considerations, and real-world applications of this concept.
Key Performance Insight: C++ Signal Handling

C++ is renowned for its efficiency. Learn how C++ Signal Handling enables low-level control and high-performance computing in the tutorial below.

In C++, signals serve as interruptions that the operating system sends to a process to halt its current operation and address the reason for the interruption. These interruptions are essential for informing the program about particular events like errors, termination requests, or external inputs. Upon receiving a signal, the operating system suspends the program's regular flow to manage the signal appropriately.

In C++, signals can be triggered by the operating system in response to system or error conditions. Interrupts can be initiated by pressing Ctrl+ C on Linux, UNIX, Mac OS X, or Windows operating systems.

When a signal is given, the system can:

  • Terminate the program.
  • Pause it
  • Just ignore it.
  • Alternatively, invoke a programmer-defined custom handler function.
  • Catching and Handling Signals

In C++, there are signals that cannot be captured or managed. Certain signals like SIGKILL or SIGSTOP are non-catchable and are enforced by the operating system to maintain system integrity. On the other hand, signals like SIGINT, SIGFPE, SIGSEGV, and SIGTERM can be captured and processed within a software application.

If signals manipulation is required in C++, incorporate the <csingnal> header. This header offers signal names and functionalities like signal for connecting a handler with a signal.

C++ Simple Signal Handling Example:

Let's consider a scenario to demonstrate how signal handling works in C++.

Example

Example

#include <iostream>

using namespace std;   //using standard namespace

int main()   //main function

{

    while (true) 

    {

        cout << "Hello, World!!\n";

    }

    return 0;

}

Output:

Output

Hello, World!!

Hello, World!!

Hello, World!!

Hello, World!!

Hello, World!!

Explanation:

In this instance, we are generating a perpetual loop that outputs the phrase "Hello, World!!" to the console. Upon pressing Ctrl+C, the system triggers the SIGINT signal, causing an interruption and the subsequent termination of the program that is currently executing.

Common Signals in C++ with their Purpose

Here is a compilation of various categories of signals in C++. The following are a few of them:

Signal Description
SIGABRT It occurs when a program calls the abort() function. It leads to abnormal termination.
SIGFPE Triggered by errors in arithmetic, such as division by zero or numeric overflow.
SIGILL It is used when the processor detects an illegal or undefined machine instruction.
SIGINT It is used when the user interrupts the program (e.g., pressing Ctrl+C).
SIGSEGV It occurs when a program tries to access memory it doesn't have permission to, like dereferencing a null or invalid pointer.
SIGTERM It is commonly used to send the termination request using the kill or other methods.
SIGHUP It is used when a terminal is closed or the controlling process ends. It is used to detect hang-ups.
SIGQUIT It is similar to SIGINT, but also generates a core dump. It typically triggered by Ctrl+\.
SIGTRAP It is used by debuggers to trigger breakpoints or trap conditions.
SIGBUS It is raised when a process accesses memory incorrectly at a hardware level (e.g., misaligned memory access).
SIGUSR1 It is reserved for user-defined behavior. Developers can assign custom actions when this signal is received.
SIGUSR2 It is another user-defined signal, similar to SIGUSR1.
SIGALRM It is used when a timer set by the alarm() function expires. Commonly used for timeouts.
SIGCONT It is used to resume a process that has been paused (e.g., after SIGSTOP).
SIGSTOP It stops (pauses) a process immediately. It cannot be caught, blocked, or ignored.

Signal function

In the C++ programming language, the signal function belongs to the signal-handling library, detailed in the header file. This function enables our program to react to unforeseen occurrences like interruptions or illegal operations through personalized signal management.

Syntax

It has the following syntax:

Example

void (*signal(int sig, void *func(int)))(int);

In this syntax:

  • sig: The signal number (e.g., SIGINT, SIGTERM) that we want to handle.
  • func: A pointer to a function to be called when the signal is received.
  • return value: The return value is a pointer to the preceding signal handler.
  • Ways to Handle Signals with signal function

If the signal function is invoked, we need to define the desired reaction of our program to the signal at hand. There are three main choices available to us:

1) Default Action - SIG_DFL

In C++, this directs the system to execute the default action associated with the signal. This could involve actions such as program termination or generating a core dump.

2) Ignore Signal - SIG_IGN

It enables the application to ignore the signal entirely. The signal is recognized but not responded to. The program proceeds as normal since no action is taken.

3) Custom Function Handler

In C++, we have the ability to define our custom signal-handling function. Upon receiving a signal, this designated function is invoked, allowing us to determine the appropriate action for the application to take (such as storing data, displaying a message, releasing resources, etc.).

C++ Signal Handling Example

Let's consider an instance to demonstrate signal management in C++.

Example

Example

#include <iostream>

#include <csignal>

#include <unistd.h> 

using namespace std;    //using standard namespace

void my_handler(int signum) 

{

    cout << "\nInterrupt signal (" << signum << ") received. Program will now terminate.\n";

    exit(signum);

}

int main()   //main function

{

    signal(SIGINT, my_handler);

    cout << "The program is running. Press Ctrl+C to stop the flow..\n";

    while (true) 

    {

        cout << "Running...\n";

        sleep(1); 

    }

    return 0;

}

Output:

Output

The program is running. Press Ctrl+C to stop the flow..

Running...

Running...

Running...

Running...

Running...

Explanation:

In this instance, we employ an infinite loop to display "Executing..." every single second. Following this, upon the user triggering Ctrl+C, the custom handler my_handler intercepts the SIGINT signal, outputs a concluding message, and elegantly halts the program.

raise Function

In C++, the raise function dispatches a signal to the ongoing process. It is straightforward to apply and appropriate for evaluating signal handlers within the application.

Syntax

It has the following syntax:

Example

int raise(int signal_type);

In this syntax,

signal_type: The signal number to be sent for handling. It can take one of the following values:

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

Return Value: When the signal is successfully delivered, the function returns 0. In case of failure, it returns a non-zero value.

C++ raise function Example

Let's consider a scenario to demonstrate the raise function in C++.

Example

Example

#include <csignal>

#include <iostream>

using namespace std;   //using standard namespace

void Signal_Handler(int s) 

{

    cout << "Interrupt is handled. Signal number is: " << s << endl;

    exit(s);  

}

int main()    //main function

{

    signal(SIGINT, Signal_Handler);

    raise(SIGINT);

    return 0;

}

Output:

Output

Interrupt is handled. Signal number is: 2

Explanation:

In this instance, we employ the raise method to manually trigger the SIGINT signal, typically triggered by pressing Ctrl+C. Upon invoking the raise(SIGINT) function, the designated custom handler Signal_Handler captures the signal, displays the signal number, and then concludes the program.

C++ Example using several raise Functions

Let's consider an example to demonstrate the various uses of the raise function in C++.

Example

Example

#include <iostream>

#include <csignal>

#include <unistd.h> 

using namespace std;   //using standard namespace

void Signal_Handler(int sig_no)

{

cout << "Interrupt is handled and the Signal number is: " << sig_no << endl;

}

void DisplayingMenu() 

{

    cout << "\nChoose a signal to raise which displayed below:\n";

    cout << "1. SIGINT (Ctrl+C simulation)\n";

    cout << "2. SIGILL (Illegal Instruction)\n";

    cout << "3. SIGALRM (Timer Alarm)\n";

    cout << "4. SIGFPE (Division by Zero)\n";

    cout << "5. SIGSEGV (Invalid Memory Access)\n";

    cout << "6. Exit out of the program.\n";

    cout << "Enter your choice which is from 1 to 6: ";

}

int main()   //main function

{

    signal(SIGINT, Signal_Handler);   

    signal(SIGILL, Signal_Handler);   

    signal(SIGALRM, Signal_Handler);  

    signal(SIGFPE, Signal_Handler);   

    signal(SIGSEGV, Signal_Handler);  

    int user_choice;

    while (true) 

    {

        DisplayingMenu();

        cin >> user_choice;

        switch (user_choice) 

        {

            case 1:

                raise(SIGINT); 

                break;

            case 2:

                raise(SIGILL); 

                break;

            case 3:

                alarm(1);      

                sleep(2);      

                break;

            case 4: 

            {

                int p = 30, q = 0;

                int ans = p / q; 

                cout << "The Result is: " << ans << endl;

                break;

            }

            case 5: 

            {

                int* pntr = nullptr;

                *pntr = 25;     

                break;

            }

            case 6:

                cout << "Exiting the program." << endl;

                return 0;

            default:

                cout << "Invalid choice. Try again.\n";

        }

    }

    return 0;

}

Output:

Output

Choose a signal to raise which displayed below:

1. SIGINT (Ctrl+C simulation)

2. SIGILL (Illegal Instruction)

3. SIGALRM (Timer Alarm)

4. SIGFPE (Division by Zero)

5. SIGSEGV (Invalid Memory Access)

6. Exit out of the program.

Enter your choice which is from 1 to 6: 1

Interrupt is handled and the Signal number is: 2

Choose a signal to raise which displayed below:

1. SIGINT (Ctrl+C simulation)

2. SIGILL (Illegal Instruction)

3. SIGALRM (Timer Alarm)

4. SIGFPE (Division by Zero)

5. SIGSEGV (Invalid Memory Access)

6. Exit out of the program.

Enter your choice which is from 1 to 6: 2

Interrupt is handled and the Signal number is: 4

Choose a signal to raise which displayed below:

1. SIGINT (Ctrl+C simulation)

2. SIGILL (Illegal Instruction)

3. SIGALRM (Timer Alarm)

4. SIGFPE (Division by Zero)

5. SIGSEGV (Invalid Memory Access)

6. Exit out of the program.

Enter your choice which is from 1 to 6: 3

Interrupt is handled and the Signal number is: 14

Choose a signal to raise which displayed below:

1. SIGINT (Ctrl+C simulation)

2. SIGILL (Illegal Instruction)

3. SIGALRM (Timer Alarm)

4. SIGFPE (Division by Zero)

5. SIGSEGV (Invalid Memory Access)

6. Exit out of the program.

Enter your choice which is from 1 to 6: 6

Exiting the program.

Explanation:

In this instance, we set up custom handlers for five unique signals, and a menu-driven loop enables the user to manually send signals like SIGINT, SIGILL, SIGALRM, SIGFPE, and SIGSEGV. Based on the user's choice, each signal is intentionally raised, and the handler displays the signal number instead of ending the program unless a critical error occurs.

kill function

In contrast to the raise function, which impacts solely the current process, the kill function possesses the capability to dispatch signals to any process, encompassing the current one, granted the necessary permissions are in place.

Syntax

It has the following syntax:

Example

int kill(pid_t pid, int signal_type);
  • pid: The process ID of the target process.
  • Returns 0 for success and -1 for failure.
  • C++ kill function Example

Let's consider a scenario to demonstrate the use of the kill function in C++.

Example

Example

#include <iostream>

#include <csignal>

#include <unistd.h>

using namespace std;  //using standard namespace

void Handle_Signal(int s)

{

    cout << "Signal received: " << s << endl;

}

int main()  //main function

{

    signal(SIGINT, Handle_Signal);

    pid_t pid = getpid();

    kill(pid, SIGINT);

    return 0;

}

Output:

Output

Signal received: 2

Explanation:

In this instance, we make use of the kill method to send the SIGINT signal to the process itself, identified by the process ID obtained from getpid. Upon sending the signal, the designated custom handler Handle_Signal is triggered, showing the signal number on the terminal.

Conclusion

In summary, signal management in C++ allows applications to react to unforeseen runtime occurrences, like interruptions or shutdown demands. By utilizing the signal method and establishing signal handler functions, we can intercept and handle signals like SIGINT or SIGTERM. This approach enhances the reliability of the program, leading to more secure terminations and controlled responses in exceptional circumstances. Ultimately, signal handling proves to be crucial in systems development and applications that heavily rely on system resources.

C++ Signal Handling FAQs

1) What signal is used when a user presses Ctrl + C?

The SIGINT signal is generated when the user initiates the Ctrl + C keyboard combination within the terminal.

2) Can a program ignore a signal?

Yes, a program has the capability to disregard a signal by assigning its handler to SIG_IGN using the signal function.

3) What signal cannot be caught, blocked, or ignored in C++?

No software can detect, prevent, or disregard the SIGKILL and SIGSTOP signals.

4) What is the purpose of C++'s raise function?

In C++, the raise function is utilized to manually trigger a signal within the current process.

5) What function sends a signal to another process using its process ID?

In C++, the kill method is employed to send a signal to a particular process by specifying its Process ID (PID).

Input Required

This code uses input(). Please provide values below:

Logic Practice
Install Logic Practice
Add to home screen for a faster app-like experience