How can I handle the interrupt signal and call the destructor in C ++?

Possible duplicate:
Is the destructor called if SIGINT or SIGSTP is output?

My code is:

#include <iostream> #include <signal.h> #include <cstdlib> void handler(int) { std::cout << "will exit..." << std::endl; exit(0); } class A { public: A() {std::cout << "constructor" << std::endl;} ~A() {std::cout << "destructor" << std::endl;} }; int main(void) { signal(SIGINT, &handler); A a; for (;;); return 0; } 

When I pressed Ctrl-C, it printed:

 constructor ^Cwill exit... 

The destructor is not printed. So how can I get out clean?

+6
source share
5 answers

With difficulties. Already the code you wrote has undefined behavior; You are not allowed to output the stream to a signal handler; In this case, you are not allowed to call exit . (I base my claims here on the Posix standard. In pure C ++, all you are allowed to do is assign a variable of type sig_atomic_t .)

In a simple case, such as your code, you can do something like:

 sig_atomic_t stopFlag = 0; void handler( int ) { stopFlag = 1; } int main() { signal( SIGINT, &handler ); A a; while ( stopFlag == 0 ) { } std::cout << "will exit..." << std::endl; return 0; } 

Depending on the application, you can do something like this by checking stopFlag in the appropriate places. But in general, if you try this, there will be race conditions: you check stopFlag before starting an intersystem system call, then a call; the signal arrives between the check and the call, you make the call, and this does not interrupt. (I used this technique, but in an application where the only intermittent system call was a socket read with a very short timeout.)

As a rule, at least in Posix you will have to create a signal processing thread; this can then be used to cleanly close all other threads. Basically, you start by setting the signal mask for all signals, then in the signal processing stream, after starting, set it to accept the signals of interest to you and call sigwait() . This implies, however, that you follow all the usual steps necessary for a clean shutdown of threads: the signal processing thread must know about all other threads, call pthread_cancel on them, etc., and you must generate the correct code for the pthread_cancel to handle, or you need to develop some other ways to ensure that all threads are properly notified. (One would hope that today all compilers handle pthread_cancel correctly. But no one knows; this is a significant execution cost and is usually not required.)

+11
source

Memory must still be freed. but if you have some code to process, I think you will have to keep track of all your objects and then destroy them as needed (for example, if the constructor adds them to std::set and the destructor deletes them again). However, this would not provide the proper order of destruction (which may require a more complex solution).

You can also use a signal handler to set some flag that leaves an infinite loop (or what you do in the main loop), instead of just ending with exit() .

+2
source

You need to exit the main scope in order for the destructor to work:

 #include <iostream> #include <signal.h> #include <cstdlib> bool stop = false; void handler(int) { std::cout << "will exit..." << std::endl; stop = true; } class A { public: A() {std::cout << "constructor" << std::endl;} ~A() {std::cout << "destructor" << std::endl;} }; int main(void) { A a; signal(SIGINT, &handler); for (;!stop;); return 0; } 
+2
source

This is because the context of the normal code and the signal handler is different. If you put the variable a in the global scope (that is, outside of any function), you will see that the destructor is called correctly.

If you want to handle cleaning yourself (instead of letting the runtime and the OS handle it), you can have a conditional loop, something like this:

 bool keep_running = true; void handler(int) { std::cout << "will exit..." << std::endl; keep_running = false; } int main(void) { signal(SIGINT, &handler); A a; while (keep_running); return 0; } 
+2
source

exit exits the process almost immediately; in particular, objects with automatic storage are not destroyed. Streams are also blurry and closed, but you cannot touch streams from within the signal handler. So that...

Just don't call exit from the signal handler; set some atomic flag to instruct the end of the loop.

 #include <iostream> #include <signal.h> #include <cstdlib> sig_atomic_t exitRequested = 0; void handler(int) { std::cout << "will exit..." << std::endl; exitRequested = 1; } struct A { A() { std::cout << "constructor" << std::endl; } ~A() { std::cout << "destructor" << std::endl; } }; int main() { signal(SIGINT, &handler); A a; for (; !exitRequested; ); } 
+1
source

Source: https://habr.com/ru/post/910233/


All Articles