πΆ C++ Signal Handling β Capture and Respond to OS-Level Interrupts
π§² Introduction β Why Signal Handling Matters in C++
C++ applications often run in environments where external interrupts or unexpected conditionsβlike Ctrl+C, segmentation faults, or timer expirationsβcan occur. Signal handling allows your program to intercept and react to such events gracefully, instead of crashing or behaving unpredictably.
π― In this guide, youβll learn:
- What signals are in C++
- How to use
signal()and define signal handlers - Common signal types (
SIGINT,SIGSEGV,SIGTERM) - Best practices for safe and clean signal management
π What Is Signal Handling?
A signal is a notification sent to a process by the operating system or another process to indicate an event. Signal handling lets you define a custom function (handler) to respond when a signal is received.
π» Code Example β With Output
β
Example: Handling Ctrl+C Interrupt (SIGINT)
#include <iostream>
#include <csignal>
using namespace std;
void signalHandler(int signum) {
cout << "\nInterrupt signal (" << signum << ") received.\n";
// Cleanup and exit
exit(signum);
}
int main() {
signal(SIGINT, signalHandler); // Handle Ctrl+C
while (1) {
cout << "Running...\n";
sleep(1);
}
return 0;
}
π’ Output when Ctrl+C is pressed:
Running...
Running...
Interrupt signal (2) received.
π§ Common C++ Signals
| Signal | Value | Description |
|---|---|---|
SIGINT | 2 | Interrupt from keyboard (Ctrl+C) |
SIGTERM | 15 | Termination signal |
SIGABRT | 6 | Abnormal termination (e.g., abort()) |
SIGSEGV | 11 | Invalid memory access (segfault) |
SIGFPE | 8 | Floating point error (e.g., divide by 0) |
SIGILL | 4 | Illegal instruction |
π§ Using signal() Function
void signal(int signum, void (*handler)(int));
signum: The signal number (e.g.,SIGINT)handler: Function to handle the signal
π§ͺ Handling SIGFPE (Divide by Zero)
#include <csignal>
#include <iostream>
using namespace std;
void handler(int signum) {
cout << "Floating point exception (divide by zero)!\n";
exit(signum);
}
int main() {
signal(SIGFPE, handler);
int a = 1 / 0; // Triggers SIGFPE
}
π Note: Behavior may vary by system/compiler. Use with caution.
π Safe Signal Handling Practices
- Keep signal handlers short and simple
- Avoid using non-reentrant functions like
printf(usewrite()instead) - Use
volatile sig_atomic_tfor shared variables accessed in signal handlers
π Summary Table β signal() vs raise()
| Function | Purpose |
|---|---|
signal() | Registers a signal handler |
raise() | Sends a signal to the current process |
kill(pid, x) | Sends signal x to another process with PID |
π‘ Best Practices & Tips
π Best Practice: Use signal handlers for graceful shutdowns, not complex logic.
π‘ Tip: Combine signal handling with atexit() to ensure cleanup functions run.
β οΈ Pitfall: Avoid calling malloc, printf, or new inside signal handlersβthey may not be safe.
π οΈ Use Cases for Signal Handling
π« Interrupt Handling: Gracefully stop on Ctrl+C
π‘ Logging Failures: Capture segmentation faults for diagnostics
π¦ Process Cleanup: Close files, deallocate memory on SIGTERM
π Watchdog Systems: Reset logic on certain fault conditions
π Secure Applications: Control sensitive operations on abnormal exit
π Summary β Recap & Next Steps
π Key Takeaways:
- Signals let you intercept OS-level events like interrupts or segmentation faults
- Use
signal()to define handlers - Keep handlers simple and clean to avoid unsafe behavior
βοΈ Real-World Relevance:
Used in daemons, CLI tools, background services, embedded systems, and fault-tolerant enterprise software.
β Next Steps:
- Learn about C++ Dynamic Memory Management
- Understand how to manage heap memory using
new,delete, andsmart pointers
βFAQ β C++ Signal Handling
βWhat is a signal in C++?
β
A signal is a message sent to a process to notify it of an event (e.g., SIGINT on Ctrl+C).
βCan all signals be caught?
β No. Some signals like SIGKILL and SIGSTOP cannot be caught or ignored.
βWhat happens if no handler is defined?
π« Default behavior (usually termination) is executed by the OS.
βCan I handle multiple signals?
β
Yes. You can register different handlers for each signal.
βIs signal() portable across systems?
β οΈ It’s standardized but may behave differently across Unix, Linux, and Windows.
