Signal and Interrupt Handling in C++

Signal and Interrupt Handling in C++

In operating systems, signals and interrupts are two important process control mechanisms. Signals are typically used to notify a program of certain events, while interrupts are responses to hardware events or changes in conditions. In C++ programming, using signals allows for asynchronous event handling, making it crucial to master them for developing efficient and responsive software applications.

Introduction to Signals

A signal is a soft interrupt used to notify a running program that a specific event has occurred. For example, signals can be used to handle user input, program exceptions, and more. The C++ language provides related functionality through the <span>signal.h</span> header file.

Common Signal Types

  • <span>SIGINT</span>: Generated by the keyboard, typically triggered when Ctrl+C is pressed.
  • <span>SIGTERM</span>: Used to request process termination.
  • <span>SIGSEGV</span>: Generated when illegal memory access occurs.

Signal Handling Functions

To handle these temporary events, we need to define a signal handling function. This function will be executed when the corresponding signal is caught.

Defining a Simple Signal Handler

The following example code demonstrates how to define and use a simple SIGINT signal handler:

#include <iostream>
#include <csignal>
#include <unistd.h>

void signalHandler(int signum) {
    std::cout << "Caught signal: " << signum << ", exiting gracefully..." << std::endl;
    exit(signum);
}

int main() {
    // Register SIGINT signal handler
    signal(SIGINT, signalHandler);
    while (true) {
        std::cout << "Running... Press Ctrl+C to trigger SIGINT." << std::endl;
        sleep(1); // Pause for 1 second to reduce output speed
    }
    return 0;
}

Code Explanation:

  1. Including Header Files: We include the necessary header files <span><csignal></span> and <span><unistd.h></span>. The former is used to register and manage our custom logic; the latter provides the sleep function to reduce output frequency.

  2. Defining signalHandler: This is our custom signal handling function, which will be called when a specified type of signal (such as SIGINT) is caught. In this function, we print the received information and exit the program.

  3. Main Program Logic: Using the <span>signal()</span> function, we associate SIGINT with our <span>signalHandler</span>. If you press Ctrl+C, the interrupt will be caught and this handler will be called.

  4. Entering an Infinite Loop: In an infinite loop, we print a message once per second. This allows us to observe how the corresponding behavior changes when Ctrl+C is triggered.

Introduction to Interrupts

Unlike software-generated signals, interrupts primarily originate from hardware or external devices, such as timers, mice, and network adapters. When these devices require the CPU’s attention (for example, when there is data to be read), they send an interrupt request (IRQ).

General Workflow of Interrupts:

  1. An external device generates an interrupt request.
  2. The CPU completes the current instruction and pauses its execution.
  3. The CPU saves the current state and transfers control to the interrupt service routine (ISR).
  4. After the ISR completes, it returns to the previously saved location to continue executing the original task.

C++ and Direct Interrupt Handling

Directly capturing hardware-level interrupts from C++ is a very complex and platform/architecture-dependent method. In most cases, the operating system abstracts this need through APIs. However, operating system development or writing drivers can achieve lower-level access using general languages—such as assembly language!

But in typical user-level application programming environments, the above methods are not applicable. Therefore, specific details are rarely mentioned, as many advanced features are encapsulated through libraries, allowing you to focus solely on your business logic!

Conclusion

This article primarily introduces the basic concepts of C++, including various common causes of process termination. The key takeaway is to apply mature idioms, and a deeper understanding of low-level interactions can be aided by other tools. At the same time, by combining corresponding examples, we can deepen our understanding through code practice, laying a foundation for future learning. Although the actual situation is more complex, this article aims to clearly and concisely open a door for you to understand this topic.

Leave a Comment