Cpp Signal Handling
# C++ Signal Handling
In C++, signals are interrupts delivered by the operating system to a running process. These interrupts can terminate a program prematurely or trigger specific behaviors. Signals can be generated by the system (such as a memory access violation), by user actions (such as pressing `Ctrl+C` in the terminal), or programmatically by the application itself.
While some signals cannot be intercepted or ignored, many can be caught and handled. This allows your program to perform cleanup operations, save state, or terminate gracefully. The macros and functions required for signal handling are defined in the `` header file.
---
## Standard C++ Signals
The following table lists the standard signals defined in `` that can be caught and handled within a C++ program:
| Signal | Description |
| :--- | :--- |
| **`SIGABRT`** | Abnormal termination of the program, such as when calling the `abort` function. |
| **`SIGFPE`** | Erroneous arithmetic operation, such as division by zero or an operation causing an overflow. |
| **`SIGILL`** | Detection of an illegal instruction. |
| **`SIGINT`** | Interactive attention signal (usually generated by the user pressing `Ctrl+C`). |
| **`SIGSEGV`** | Invalid memory access (segmentation fault). |
| **`SIGTERM`** | Termination request sent to the program. |
---
## The `signal()` Function
The C++ signal-handling library provides the `signal()` function to trap and handle unexpected events or interrupts.
### Syntax
The formal prototype of the `signal()` function can look intimidating:
```cpp
void (*signal(int sig, void (*func)(int)))(int);
```
To make it easier to understand, you can think of it as:
```cpp
signal(registered_signal, signal_handler);
```
### Parameters and Return Value
* **`registered_signal`**: The integer identifier of the signal you want to catch (e.g., `SIGINT`, `SIGTERM`).
* **`signal_handler`**: A pointer to the function that will handle the signal. This function must accept a single `int` argument (the signal number) and return `void`. You can also pass special macros:
* `SIG_DFL`: Reverts the signal handling to the default operating system behavior.
* `SIG_IGN`: Ignores the signal completely.
* **Return Value**: The function returns a pointer to the previously defined signal handler. If no handler was previously set, it returns `SIG_DFL` or `SIG_IGN`.
---
## Code Examples
### 1. Catching an External Signal (`SIGINT`)
The following example demonstrates how to register a signal handler for `SIGINT` (triggered by pressing `Ctrl+C` in your terminal).
```cpp
#include
#include
#include
// On POSIX systems (Linux/macOS), provides sleep()
// On Windows, you can use and Sleep()
#ifdef _WIN32
#include
#define sleep(x) Sleep((x) * 1000)
#else
#include
#endif
using namespace std;
// Define the signal handler function
void signalHandler(int signum) {
cout << "\nInterrupt signal (" << signum << ") received." << endl;
// Perform cleanup operations here (e.g., closing files, releasing resources)
cout << "Cleaning up and exiting..." << endl;
// Terminate the program
exit(signum);
}
int main() {
// Register the SIGINT signal and associate it with signalHandler
signal(SIGINT, signalHandler);
cout << "Program running. Press Ctrl+C to interrupt..." << endl;
while (true) {
cout << "Going to sleep..." << endl;
sleep(1);
}
return 0;
}
```
#### Expected Output:
If you run the program and press `Ctrl+C` after a few seconds, the output will look like this:
```text
Program running. Press Ctrl+C to interrupt...
Going to sleep...
Going to sleep...
Going to sleep...
^C
Interrupt signal (2) received.
Cleaning up and exiting...
```
---
### 2. Raising Signals Programmatically with `raise()`
You can manually trigger a signal from within your program using the `raise()` function.
### Syntax
```cpp
int raise(int sig);
```
Here, `sig` is the signal number you want to send to the current process.
### Example
The following program uses `raise()` to trigger a `SIGINT` signal automatically after looping three times:
```cpp
#include
#include
#include
#ifdef _WIN32
#include
#define sleep(x) Sleep((x) * 1000)
#else
#include
#endif
using namespace std;
// Define the signal handler function
void signalHandler(int signum) {
cout << "\nInterrupt signal (" << signum << ") received." << endl;
// Perform cleanup and exit
exit(signum);
}
int main() {
int i = 0;
// Register the SIGINT signal and associate it with signalHandler
signal(SIGINT, signalHandler);
while (++i) {
cout << "Going to sleep..." << endl;
// Programmatically trigger SIGINT when i reaches 3
if (i == 3) {
cout << "Raising SIGINT programmatically..." << endl;
raise(SIGINT);
}
sleep(1);
}
return 0;
}
```
#### Expected Output:
```text
Going to sleep...
Going to sleep...
Going to sleep...
Raising SIGINT programmatically...
Interrupt signal (2) received.
```
---
## Important Considerations & Best Practices
When working with signal handlers in production C++ applications, keep the following safety rules in mind:
1. **Asynchronous Signal Safety**: Signal handlers run asynchronously and can interrupt your program at any point. Inside a signal handler, you should **only** call lock-free, async-signal-safe functions.
2. **Avoid I/O and Allocation**: Functions like `std::cout`, `printf()`, `malloc()`, or the `new` operator are **not** async-signal-safe. Calling them inside a signal handler can lead to deadlocks or undefined behavior if the program was interrupted while executing those same functions. (Note: The examples above use `std::cout` for demonstration purposes only).
3. **Use `volatile std::sig_atomic_t`**: If you need to share a flag between your main program loop and the signal handler, declare it as `volatile std::sig_atomic_t`. This guarantees that reads and writes to the variable are atomic and cannot be interrupted.
```cpp
#include
volatile std::sig_atomic_t keep_running = 1;
void handle_sig(int) {
keep_running = 0; // Safe
}
```
4. **Platform Differences**: Signal handling behavior can vary significantly between POSIX systems (Linux, macOS) and Windows. For robust, production-grade Unix applications, consider using the POSIX-specific `sigaction()` function instead of `signal()`, as it offers more reliable and configurable signal-handling behavior.
YouTip