Is Destructor Called If Sigint or Sigstp Issued

Is destructor called if SIGINT or SIGSTP issued?

No, by default, most signals cause an immediate, abnormal exit of your program.

However, you can easily change the default behavior for most signals.

This code shows how to make a signal exit your program normally, including calling all the usual destructors:

#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <cstring>
#include <atomic>

std::atomic<bool> quit(false); // signal flag

void got_signal(int)
{
// Signal handler function.
// Set the flag and return.
// Never do real work inside this function.
// See also: man 7 signal-safety
quit.store(true);
}

class Foo
{
public:
~Foo() { std::cout << "destructor\n"; }
};

int main(void)
{
struct sigaction sa;
memset( &sa, 0, sizeof(sa) );
sa.sa_handler = got_signal;
sigfillset(&sa.sa_mask);
sigaction(SIGINT,&sa,NULL);

Foo foo; // needs destruction before exit
while (true)
{
// do real work here...
sleep(1);
if( quit.load() ) break; // exit normally after SIGINT
}
return 0;
}

If you run this program and press control-C, you should see the word "destructor" printed.

Be aware that your signal handler function (got_signal) should rarely do any work, other than setting a flag and returning quietly, unless you really know what you are doing. See also: https://man7.org/linux/man-pages/man7/signal-safety.7.html

Most signals are catchable as shown above, but not SIGKILL, you have no control over it because SIGKILL is a last-ditch method for killing a runaway process, and not SIGSTOP which allows a user to freeze a process cold. Note that you can catch SIGTSTP (control-Z) if desired, but you don't need to if your only interest in signals is destructor behavior, because eventually after a control-Z the process will be woken up, will continue running, and will exit normally with all the destructors in effect.

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

With difficulty. Already, the code you've written has undefined
behavior; you're not allowed to output to a stream in a signal handler;
for that matter, you're not allowed to call exit either. (I'm basing
my assertions here on the Posix standard. In pure C++, all you're
allowed to do is assign to a variable of sig_atomic_t type.)

In a simple case like your code, you could 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 may be able to do something like this,
checking the stopFlag at appropriate places. But generally, if you
try this, there will be race conditions: you check stopFlag before
starting an interuptable system call, then do the call; the signal
arrives between the check and the call, you do the call, and it isn't
interrupted. (I've used this technique, but in an application where the
only interruptable system call was a socket read with a very short
timeout.)

Typically, at least under Posix, you'll end up having to create a signal
handling thread; this can then be used to cleanly shut down all of the
other threads. Basically, you start by setting the signal mask to block
all signals, then in the signal handling thread, once started, set it to
accept the signals you're interested in and call sigwait(). This
implies, however, that you do all of the usual actions necessary for a
clean shutdown of the threads: the signal handling thread has to know
about all other threads, call pthread_cancel on them, etc., and you're
compiler has to generate the correct code to handle pthread_cancel, or
you need to develop some other means of ensuring that all threads are
correctly notified. (One would hope, today, that all compilers handle
pthread_cancel correctly. But one never knows; doing so has
significant runtime cost, and is not usually needed.)

Program structure to catch SIGINT and call destructor in C++

Perhaps you could put a loop in your run_simulation() routine instead of the main loop. The loop in this routine waits for the aformentioned "global" volatile atomic variable. This would allow your routine to finish before shutting itself down

// included stuff

// flag
volatile sig_atomic_t no_signal = 1;

void sig_handler(int)
{
--no_signal;
}

void run_simulation(...)
{
// Maybe you put stuff on heap
CMyClass* pMyObj = new CMyClass;

do // at least once
{
// Maybe some stack stuff
CMyClass oMyObj; // Dtor called when scope ends

// Here you could already check if the signal has occurred,
// to shut down in a timely manner
if (no_signal)
p_MyObj->do_stuff_that_takes_1_hour()
else
break;

} while (no_signal)

// clean up stuff
delete p_MyObj;
p_MyObj = nullptr; // if c++11
}

int Main()
{
// Register sighandler

// set up variables

HDF5Writer writer(...);
run_simulation(&writer, [params]);

return 0;
}

Behavior of smart pointers when process is killed

That is to be expected: the default signal handlers will effectively call exit() in your process, which will terminate the process. To get around this you should install a signal handler and take appropriate action when receiving a signal.

How to deal with SIGINT?

If your application is shutting down, don't worry about memory. The OS is going to throw it all away once you terminate anyway.

The things you need to clean up in your signal handler is stuff that's going to outlive your process otherwise - for example, if a child process you've created needs to exit also, you should tell it to do so.

Calling shared libraries without releasing the memory

So, if you do use this api correctly then it requires you to do proper clean up after use (which is not really user friendly).

First of all, if you really need to use Ctrl-C, allow program to end properly on this signal: Is destructor called if SIGINT or SIGSTP issued?

Then use a technique with a stack object containing a resource pointer (to a CloseAPI function in this case). Then make sure this object will call CloseAPI in his destructor (you may want to check if CloseAPI wasn't called before). See more in "Effective C++, Chapter 3: Resource Management".

That it, even if you don't call CloseAPI, pointer container will do it for you.

p.s. you should considering doing it even if you're not going to use Ctrl-C. Imagine exception occurred and your program has to be stopped: then you should be sure you don't leave OS in an undefined state.



Related Topics



Leave a reply



Submit