Относится к Как я могу обработать сигнал прерывания и вызвать деструктор в C ++?, но мой вопрос вращается вокруг структурирования программы.
Я пишу программу моделирования, которая записывает данные в файл HDF5. Но в случае прерывания программы я бы хотел, чтобы HDF5 был правильно закрыт, чтобы накопленные данные оставались читаемыми. Я написал класс писателя HDF5, который содержит дескрипторы файла HDF5, и если вызывается деструктор этого класса, файл HDF5 должен быть закрыт. Следовательно, в случае прерывания программы с помощью Ctrl-C я бы хотел перехватить SIGINT и вызвать деструктор.
Согласно моим прочтениям, в том числе Вызывается ли деструктор, если выдается SIGINT или SIGSTP?, функция обработчика для sigaction
должно быть очень простым, не более чем изменение флага. Это приводит к программе, подобной следующей (скопировано со второй ссылки) …
#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;
}
Вы можете увидеть в структуре программы, что часть внутри while
Цикл должен быть достаточно коротким, чтобы программа проверяла флаг quit
часто. Но моя проблема в том, что моя программа структурирована так:
int main()
{
// set up variables
HDF5Writer writer(...);
run_simulation(&writer, [params]);
}
run_simulation
будет запускать мое моделирование до тех пор, пока не будут выполнены указанные критерии остановки, что может занять несколько минут / часов. Как мне настроить мою программу для отслеживания какого-либо флага, чтобы он своевременно завершал работу после получения SIGINT?
Возможно, вы могли бы поместить цикл в подпрограмму run_simulation () вместо основного цикла. Цикл в этой подпрограмме ожидает упомянутой «глобальной» изменчивой атомарной переменной. Это позволит вашей рутине закончить, прежде чем отключиться
// 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;
}
Других решений пока нет …