Table of Contents
Handling signals and interrupts is a crucial aspect of C programming, especially when developing applications that interact with hardware or require real-time responsiveness. Signals are notifications sent to a process to notify it of events like user requests or hardware conditions. Proper handling ensures your program can respond gracefully to such events.
Understanding Signals in C
Signals are asynchronous notifications sent to a process to notify it of various events. Common signals include SIGINT (interrupt from keyboard), SIGTERM (termination request), and SIGKILL (forceful kill). When a signal occurs, the default action might be to terminate the program, but you can customize this behavior by defining signal handlers.
Setting Up Signal Handlers
To handle signals, you need to define a signal handler function and register it using the signal() or sigaction() functions. The sigaction() function provides more control and is recommended for modern applications.
Example Using signal()
Here’s a simple example of handling SIGINT (Ctrl+C) to gracefully exit a program:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
void handle_sigint(int sig) {
printf("Caught signal %d, exiting...\n", sig);
exit(0);
}
int main() {
signal(SIGINT, handle_sigint);
while (1) {
printf("Running... Press Ctrl+C to exit.\n");
sleep(1);
}
return 0;
}
Using sigaction()
The sigaction() function offers more flexibility, such as controlling signal masks and flags. Here's how to set it up:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
void handle_sigint(int sig) {
printf("Handled SIGINT (%d). Exiting now.\n", sig);
exit(0);
}
int main() {
struct sigaction sa;
sa.sa_handler = handle_sigint;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGINT, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
while (1) {
printf("Waiting for Ctrl+C...\n");
sleep(1);
}
return 0;
}
Best Practices for Signal Handling
- Keep signal handlers simple and avoid complex logic or I/O operations.
- Use
volatile sig_atomic_tvariables for shared data between handlers and main code. - Restore original signal handlers if necessary after handling a signal.
- Test signal handling thoroughly to ensure your application responds correctly under different conditions.
By understanding and properly implementing signal handling, you can create robust C programs that respond effectively to external events and hardware signals, ensuring stability and graceful shutdowns.