Sometimes we need to return something to the system when we finish a program, but it may be that the user killed the process before the end of it without being expected.
It happens a lot in programs that have a loop while
with tasks to be executed to the expected end!
Suppose you have this code that issues a warning at the beginning of the program and after 5 seconds the program ends and issues another warning:
#include <iostream>
#include <memory>
#include <chrono>
#include <thread>
void msgOut(){
std::cout << "The 5 second count has finished." << '\n';
}
class CountTime {
void m_start_count(){
std::this_thread::sleep_for(std::chrono::seconds(5));
}
public:
CountTime(){
std::cout << "The 5 second countdown has started!" << '\n';
this->m_start_count();
}
~CountTime(){
msgOut();
}
};
int main(){
auto ct = std::make_unique<CountTime>();
return 0;
}
After compiling and running, after 5 seconds these two messages appeared in the output:
The 5 second countdown has started!
The 5 second count has ended.
Now suppose that before the end of 5 seconds, you press Ctrl + c
, the second message will not appear and the output will be like this:
The 5 second countdown has started!
^C
In other words, if your program has a function to be executed whenever the program ends, then it will generate a silent bug.
To solve this, we can map the signal sent and execute a certain task even if the program is interrupted before its normally expected end.
std::signal
First let’s include the header:
#include <csignal>
Create a callback function that will handle the signal, outside the execution of our class:
void signal_handler(int signal) {
if (signal == SIGINT) {
msgOut();
std::exit(EXIT_SUCCESS);
}
}
And start it in the constructor, or before the start of a supposed loop
that we will execute!
std::signal(SIGINT, signal_handler);
The final code will be:
#include <iostream>
#include <memory>
#include <chrono>
#include <thread>
#include <csignal> // include
void msgOut(){
std::cout << "The 5 second count has finished." << '\n';
}
// Our function for handling the signal
void signal_handler(int signal) {
if (signal == SIGINT) {
msgOut();
std::exit(EXIT_SUCCESS);
}
}
class CountTime {
void m_start_count(){
std::this_thread::sleep_for(std::chrono::seconds(5));
}
public:
CountTime(){
std::signal(SIGINT, signal_handler); // Configuring signal handling
std::cout << "The 5 second countdown has started!" << '\n';
this->m_start_count();
}
~CountTime(){
msgOut();
}
};
int main(){
auto ct = std::make_unique<CountTime>();
return 0;
}
After compiling and running, after pressing Ctrl + c
, the output will now be:
The 5 second countdown has started!
^CThe 5 second count has finished.
Note that after Ctrl + c
(^C
) the message appeared normally!
while
#include <iostream>
#include <csignal>
void signal_handler(int signal) {
if (signal == SIGINT) {
std::cout << "You pressed: Ctrl + C\n";
std::exit(EXIT_SUCCESS);
}
}
auto main() -> int {
std::signal(SIGINT, signal_handler);
while (true){}
}
Output after
Ctrl + c
:
^CDou pressed: Ctrl + C
I hope it helped, for more information visit documentation about std::signal
.