Signal Handling in C: Capturing and Processing Signals

In C, a signal is an asynchronous event used to notify a program that a certain condition has occurred. Signals can be generated by the operating system, hardware, or the program itself. Common signals include process termination and illegal memory access. In this article, we will introduce how to capture and handle these signals in C.

What is a Signal?

A signal is a mechanism used to notify a process of specific events. For example, when a user presses Ctrl+C, the operating system sends a SIGINT signal to the running program, indicating that the user wishes to terminate it. Other common signals include:

  • <span>SIGTERM</span>: Request to terminate the process.
  • <span>SIGSEGV</span>: Invalid memory access (segmentation fault).
  • <span>SIGFPE</span>: Arithmetic error (e.g., division by zero).

Signal Handling Functions

To respond to specific signals, we need to define a “signal handling function”. This function will be called when the specified signal arrives. We use the <span>signal()</span> function to register this handler.

Example Code

Below is a simple example demonstrating how to capture and handle the SIGINT signal:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
// Signal handling function
void handle_sigint(int sig) {
    printf("Received SIGINT (Ctrl+C), preparing to exit...\n");
    exit(0); // Exit the program
}
int main() {
    // Register the handler for SIGINT
    signal(SIGINT, handle_sigint);
    printf("Press Ctrl+C to trigger SIGINT signal...\n");
    // Infinite loop to keep running and waiting for input
    while (1) {
        sleep(1); // Print a message every second
        printf("Program is still running...\n");
    }
    return 0;
}

Code Explanation

  1. Include Header Files:

  • <span><stdio.h></span> for input/output functions.
  • <span><stdlib.h></span> provides the exit() function.
  • <span><signal.h></span> includes functions related to signals.
  • <span><unistd.h></span> provides the sleep() function.
  • Define Signal Handling Function:

    void handle_sigint(int sig) {
        printf("Received SIGINT (Ctrl+C), preparing to exit...\n");
        exit(0);
    }

    This function is called when the SIGINT signal is received, prints a message, and safely exits the program.

  • Register Signal Handler:

    signal(SIGINT, handle_sigint);

    Using the <span>signal()</span> function, we associate our custom handler with SIGINT.

  • Main Loop: The program enters an infinite loop, printing a message every second. This allows us to observe when Ctrl+C is pressed, transferring control to our handler.

  • Considerations

    1. Reentrancy Issues:

    When writing complex signal handlers, be careful to avoid using non-reentrant library calls, such as malloc or printf, as they may lead to undefined behavior. If output is needed, consider using the <span>write()</span> system call, which is safe and reentrant.

    1. Limitations in Multithreaded Environments:

    In multithreaded applications, only the main thread can set or clear certain types of signal handlers. Therefore, special care must be taken in managing and responding to signals in multithreaded applications.

    1. Default Behavior vs. Custom Behavior:

    Each signal has a default behavior, such as ignoring or terminating the process. When you register your own handler, you can override these default behaviors, but ensure your logic aligns with expectations to avoid unintended consequences.

    Conclusion

    Through this article, you should have gained a basic understanding of signal capturing and handling in C. Mastering this technique is crucial for writing robust software that can correctly respond to external events. In practical development, it is essential to design and implement your signal handling appropriately based on requirements. We hope this article helps you better understand signals in C!

    Leave a Comment