Прервать выполнение программы и сохранить данные - PullRequest
1 голос
/ 12 августа 2011

Как спроектировать программу на C / C ++, чтобы она могла сохранять некоторые данные после получения сигнала прерывания.

У меня есть долго работающая программа, которую мне может потребоваться убить (скажем, нажав Ctrl-C), прежде чем она закончится. После уничтожения (в отличие от запуска до завершения) программа должна иметь возможность сохранять некоторые переменные на диск. У меня есть несколько больших книг по Linux, но я не очень уверен, с чего начать. Рецепт кулинарной книги был бы очень полезен.

Спасибо.!

Ответы [ 5 ]

4 голосов
/ 12 августа 2011

То, что вы хотите сделать, не тривиально.Вы можете начать с установки обработчика сигнала для SIGINT (Cc), используя signal или sigaction, но затем запустится hard part .

Основная проблема заключается в том, что в обработчике сигнала выможет вызывать только асинхронно-безопасные функции (или входящие функции).Большинство функций библиотеки не могут считаться реентерабельными.Например, stdio функции, malloc, free и многие другие не являются реентерабельными.

Так как вы справляетесь с этим?Установите flag в своем обработчике (установите некоторую глобальную переменную done в 1) и найдите ошибки EINTR.Должно быть безопасно выполнить очистку вне обработчика .

4 голосов
/ 12 августа 2011

, чтобы сделать это, вам нужно заставить вашу программу наблюдать что-то, например глобальную переменную, которая скажет ему прекратить то, что она делает.

Например, предположим, что ваша долгосрочная программа выполняетцикл, вы можете сделать это:

g_shouldAbort = 0;
while(!finished)
{
   // (do some computing)

   if (g_shouldAbort)
   {
      // save variables and stuff
      break; // exit the loop
   }
}

с g_shouldAbort, определенным как глобальная volatile переменная, например:

static volatile int g_shouldAbort = 0;

(Очень важно объявить его «volatile», иначе компилятор, видя, что никто не записывает его в цикл, может посчитать, что if (g_shouldAbort) всегда будет ложным, и оптимизировать его.)

thenиспользуя, например, API signal , который предлагали другие пользователи, вы можете сделать это:

void signal_handler(int sig_code)
{
   if (sig_code == SIGUSR1) // user-defined signal 1
      g_shouldAbort = 1;
}

(вам, конечно, нужно зарегистрировать этот обработчик, см. здесь .

signal(SIGUSR, signal_handler);

Затем, когда вы «отправляете» сигнал SIGUSR1 в вашу программу (например, с помощью команды kill ), g_shouldAbort будет установлен в 1, и ваша программа остановится.его вычисления.

Надеюсь, что это поможет!

ПРИМЕЧАНИЕ: эта техника проста, но грубая.Использование сигналов и глобальных переменных, конечно, затрудняет использование нескольких потоков, как наметили другие пользователи.

3 голосов
/ 12 августа 2011

То, что вы пытаетесь сделать, подпадает под рубрику контрольной точки / перезапуска.

Существует несколько больших проблем с использованием управляемой сигналом схемы для проверки / перезапуска.Во-первых, обработчики сигналов должны быть очень компактными и очень примитивными.Вы не можете написать контрольную точку внутри вашего обработчика сигнала.Другая проблема заключается в том, что ваша программа может быть в любом месте в состоянии выполнения при отправке сигнала.Это случайное местоположение почти наверняка не является безопасной точкой, из которой может быть сброшена контрольная точка.Еще одна проблема заключается в том, что вам нужно снабдить вашу программу возможностью проверки / перезапуска на стороне приложения.

Вместо того, чтобы использовать собственную функцию проверки / перезапуска, я предлагаю вам воспользоваться уже существующей бесплатной.GDB в Linux обеспечивает возможность контрольной точки / перезапуска.Другой - DMTCP, см. http://dmtcp.sourceforge.net/index.html.

0 голосов
/ 12 августа 2011

Сделайте ваш ввод только один раз в функции сохранения

// somewhere in main
signal( SIGTERM, signalHandler );
signal( SIGINT,  signalHandler );

void saveMyData()
{
    // save some data here
}

void signalHandler( int signalNumber )
{
    static pthread_once_t semaphore = PTHREAD_ONCE_INIT;
    std::cout << "signal " << signalNumber << " received." << std::endl;
    pthread_once( & semaphore, saveMyData );
}

Если ваш процесс получит 2 или более сигналов до того, как вы закончите запись файла, вы сохраните странные данные

0 голосов
/ 12 августа 2011

Используйте signal(2) или sigaction(2), чтобы назначить указатель функции для сигнала SIGINT и выполнить там очистки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...