Исключение не поймано после сигнала - PullRequest
0 голосов
/ 27 сентября 2018

Я пытаюсь поймать сигнал завершения в своем коде, чтобы записать файл перезапуска перед выходом.Мое решение основано на этом ответе .

#include <exception>
#include <csignal>
#include <iostream>


class InterruptException : public std::exception
  {
   public:
    InterruptException(int _s) : signal_(_s) { }
    int signal() const noexcept
    {
      return this->signal_;
    }

   private:
    int signal_;
  };

  /// method to throw exception at signal interrupt
  void sig_to_exception(int s)
  {
    throw InterruptException(s);
  }

int main()
{
  // activate signal handling
  struct sigaction sigIntHandler;
  sigIntHandler.sa_handler = sig_to_exception;
  sigemptyset(&sigIntHandler.sa_mask);
  sigIntHandler.sa_flags = 0;
  sigaction(SIGINT, &sigIntHandler, NULL);

  try
  {
    for (std::size_t i = 0; i < 100000000; ++i)
    {
      std::cout  << i << std::endl;
    }
  }
  catch (const InterruptException& e)
  {
    std::cout << "Received signal " << e.signal() << std::endl;
    std::exit(1);
  }
  catch(...)
  {
    std::cout << "Other catch!" << std::endl;
  }
}

Исключение генерируется нормально, однако мой блок catch не ловит его.Программа завершается с необработанным исключением InterruptException.Я пытался с Clang и GCC на MacOS.Любая идея, почему исключение не перехвачено правильно?

Спасибо

Вывод при компиляции с g ++ 7.3.0:

terminate called after throwing an instance of 'InterruptException'
   what():  std::exception
Abort trap: 6

Вывод при компиляции с Apple LLVM 9.0.0

libc++abi.dylib: terminating with uncaught exception of type InterruptException: std::exception

PS: Кажется, когда я компилирую с Apple LLVM, иногда ловится исключение, но не всегда, что делает это еще более странным.

Ответы [ 2 ]

0 голосов
/ 27 сентября 2018

В большинстве систем стековый фрейм, используемый обработчиком сигнала, не является стандартным фреймом стека функций, как определено компилятором для вызовов функций.

Так что исключение из обработчика sig не поддерживается.

Фрейм стека для обработки сигналов в ядре Linux

Из обсуждения в связанном вопросе, в системе Linux они даже не используют один и тот же стек для фрейма стека и возвращаюттребует возврата к системной функции для восстановления исходного стека пользователя.

Если ОС не предназначена специально для обработки исключений, это не сработает.

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

0 голосов
/ 27 сентября 2018

Очень мало что вы можете надежно сделать в обработчике сигналов.В частности, вы не можете выбросить исключение.Код в вопросе (и «ответ», на который он ссылается) в лучшем случае зависит от поведения компилятора / ОС.Ограничения на то, что вы можете сделать в обработчике сигналов, см. this .

. Обратите внимание, что ссылка выше относится к signal, что является стандартным C. sigaction не является стандартнымC, это POSIX, и определение языка C ++ не предъявляет никаких требований к программе, которая его использует.

...