1

Related to How can I handle interrupt signal and call destructor in c++?, but my question revolves around structuring a program.

I am writing a simulation program that writes data out to HDF5 file. But in case of program interruption, I'd like the HDF5 to be closed properly such that the accumulated data is still readable. I've written an HDF5 writer class that contains the handles to the HDF5 file, and if the destructor of that class is called, the HDF5 file should get closed. Hence, in the event of program interruption by Ctrl-C, I'd like to catch the SIGINT, and invoke the destructor.

According to my reading, including Is destructor called if SIGINT or SIGSTP issued?, the handler function for sigaction should be very simple, nothing more than changing a flag. This leads to a program like the following (copied from the second link)...

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

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

void got_signal(int)
{
    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;
}

You can see in the program structure that part within the while loop should be sufficiently short such that the program checks on the flag quit frequently. But my trouble is my program is structured more like this:

int main()
{
     // set up variables

     HDF5Writer writer(...);

     run_simulation(&writer, [params]);
}

run_simulation will run my simulation until specified stop criteria are fulfilled, which can take several minutes/hours. How do I setup my program to be monitoring some flag so that it shuts things down after receiving SIGINT in a timely manner?

Community
  • 1
  • 1
bernie
  • 546
  • 3
  • 13

1 Answers1

0

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;
}
Autex
  • 307
  • 2
  • 12
  • 1
    thanks. i suppose my question was too open-ended. i didn't update, but i did end up adding a monitor for the signal flag within the simulation loop – bernie Aug 14 '17 at 18:16