C++ Signaalverwerking onder de knie: Veilige interruptafhandeling en schone programmaterminatie
Wat zijn signalen?
Signalen zijn interrupts die aan een proces worden geleverd door het besturingssysteem en die een programma voortijdig kunnen beëindigen. U kunt interrupts genereren door op Ctrl+C te drukken op een UNIX-, Linux-, Mac OS X- of Windows-systeem.
Er zijn signalen die niet door het programma kunnen worden opgevangen, maar hier is een lijst met signalen die u wel in uw programma kunt vangen en waarop u passende acties kunt ondernemen. Deze signalen zijn gedefinieerd in de C++-header <csignal>.
| Nr. | Signaal & Beschrijving |
|---|---|
| 1 | SIGABRT Abnormale beëindiging van het programma, bijvoorbeeld door een aanroep van abort. |
| 2 | SIGFPE Een foutieve rekenkundige bewerking, zoals delen door nul of een overflow. |
| 3 | SIGILL Detectie van een illegale instructie. |
| 4 | SIGINT Ontvangst van een interactief aandachtssignaal (bijv. Ctrl+C). |
| 5 | SIGSEGV Ongeldige toegang tot geheugen (segmentatiefout). |
| 6 | SIGTERM Een beëindigingsverzoek dat naar het programma wordt gestuurd. |
De signal()-functie
De C++ signal-handling bibliotheek biedt de functie signal om onverwachte gebeurtenissen af te vangen. De syntaxis is als volgt:
void (*signal (int sig, void (*func)(int)))(int);
Vereenvoudigd ontvangt deze functie twee argumenten: het eerste is een integer die het signalenummer vertegenwoordigt, het tweede is een pointer naar de signal-handler functie.
Laten we een eenvoudig C++-programma schrijven waarin we het SIGINT-signaal vangen met de signal()-functie. Elk signaal dat u wilt afvangen, moet u registreren met de signal-functie en koppelen aan een signal-handler. Bestudeer het volgende voorbeeld:
#include <iostream>
#include <csignal>
using namespace std;
void signalHandler(int signum) {
cout << "Interrupt signal (" << signum << ") ontvangen.\n";
// opruimen en afsluiten
exit(signum);
}
int main() {
// registreer signaal SIGINT en signal handler
signal(SIGINT, signalHandler);
while(1) {
cout << "Ga slapen...." << endl;
sleep(1);
}
return 0;
}
Wanneer de bovenstaande code wordt gecompileerd en uitgevoerd, produceert het het volgende resultaat:
Ga slapen.... Ga slapen.... Ga slapen....
Druk nu op Ctrl+C om het programma te onderbreken. U ziet dat het programma het signaal vangt en afsluit met een bericht als:
Ga slapen.... Ga slapen.... Ga slapen.... Interrupt signal (2) ontvangen.
De raise()-functie
U kunt signalen ook zelf genereren met de functie raise(), die een integer signaalnummer als argument neemt en de volgende syntaxis heeft:
int raise (signal sig);
Hierbij is sig het signaalnummer dat u wilt sturen: SIGINT, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGTERM, SIGHUP. Hieronder een voorbeeld waarin we intern een signaal opwekken met raise():
#include <iostream>
#include <csignal>
using namespace std;
void signalHandler(int signum) {
cout << "Interrupt signal (" << signum << ") ontvangen.\n";
// opruimen en afsluiten
exit(signum);
}
int main() {
int i = 0;
signal(SIGINT, signalHandler);
while(++i) {
cout << "Ga slapen...." << endl;
if(i == 3) {
raise(SIGINT);
}
sleep(1);
}
return 0;
}
De uitvoer zal zijn:
Ga slapen.... Ga slapen.... Ga slapen.... Interrupt signal (2) ontvangen.
C Taal
- C++ datatypes begrijpen: fundamentals, modifiers en best practices
- C++ operators: complete gids met praktische voorbeelden
- C++ comments: best practices voor leesbare, onderhoudbare code
- C++ Class Templates Beheersen: Een Praktische Gids
- C Bestandsbehandeling: I/O onder de knie krijgen met fopen, fprintf, fread en fseek
- C++ Exception Handling: Praktische Try, Catch, Throw Voorbeelden
- Foutafhandeling in C: Best Practices & Technieken
- C++ Programmeertaal: Overzicht & Belangrijkste Kenmerken
- C++ Constanten & Literals Uitgelegd: Types, Syntax en Best Practices
- Uitgebreide Gids voor C++ Operators: Types, Gebruik en Best Practices
- Numerieke Typen in C++ Beheersen: Een Praktische Gids