Как гарантировать, что код очистки запускается в Windows C ++ (SIGINT, неверное размещение и закрытое окно) - PullRequest
3 голосов
/ 08 марта 2010

У меня есть консольная программа для Windows C ++, и если я не вызываю ReleaseDriver() в конце моей программы, некоторые компоненты оборудования переходят в плохое состояние и не могут быть снова использованы без перезагрузки. Я хотел бы убедиться, что ReleaseDriver() запускается даже в случае ненормального выхода из программы, например, если я нажму Ctrl+C или закрою окно консоли.

Я могу использовать signal() для создания обработчика сигнала для SIGINT. Это работает нормально, хотя, когда программа заканчивается, появляется всплывающая ошибка «Произошло необработанное исключение Win32 ...».

Я не знаю, как обращаться со случаем закрытия окна консоли, и (что более важно) я не знаю, как обрабатывать исключения, вызванные неправильным доступом к памяти и т. Д.

Спасибо за любую помощь!

Ответы [ 3 ]

3 голосов
/ 08 марта 2010

Если я не ошибаюсь, вы можете определить, закрыта ли консоль или программа закрывается с помощью Ctrl + C с помощью SetConsoleCtrlHandler:

#include <windows.h>

BOOL CtrlHandler(DWORD)
{
    MessageBox(NULL, "Program closed", "Message", MB_ICONEXCLAMATION | MB_OK);
    exit(0);
}

int main()
{
    SetConsoleCtrlHandler((PHANDLER_ROUTINE)&CtrlHandler, TRUE);
    while (true);
}

Если вы беспокоитесь об исключениях, таких как bad_alloc, вы можете заключить main в блок try. Catch std::exception&, который в идеале должен быть базовым классом для всех выданных исключений, но вы также можете перехватить любое исключение C ++ с помощью catch (...). Однако с этими исключениями не все потеряно, и вы должны выяснить, что бросается и почему.

Также помогает избежать неопределенного поведения. :)

3 голосов
/ 08 марта 2010

В Windows вы можете создать фильтр необработанных исключений, вызвав SetUnhandledExceptionFilter () . После этого в любое время, когда генерируется исключение, которое не обрабатывается где-либо в вашем приложении, будет вызван ваш обработчик.

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

Обратите внимание, что существует множество «ошибок», связанных с тем, как вы пишете свою функцию обработчика исключений. В частности:

  1. Вы не можете вызвать любую функцию CRT, такую ​​как new
  2. Вы не можете выполнять выделение на основе стека
  3. Если вы сделаете в обработчике что-нибудь, что вызовет исключение, Windows немедленно прекратит работу вашего приложения, вырвав кости из его спины. У вас больше нет шансов изящно отключиться.

Вы можете вызывать многие функции Windows API. Но вы не можете sprintf, new, delete ... Короче говоря, если это не функция WINAPI, это, вероятно, небезопасно.

Из-за всего вышесказанного желательно, чтобы все переменные в вашем обработчике static были переменными. Вы не сможете использовать sprintf, поэтому вам придется форматировать строки заранее, во время инициализации. Просто помните, что машина находится в очень нестабильном состоянии, когда вызывается ваш обработчик.

1 голос
/ 08 марта 2010

Вы не можете (код гарантии запускается). Вы можете потерять власть, тогда ничего не получится. Кэш инструкций L1 вашего ЦП может перегореть, тогда ваш код будет ошибаться случайным образом.

Самый верный способ запуска кода очистки - это отдельный процесс, который отслеживает выход первого (просто WaitForSingleObject в дескрипторе процесса). Отдельный сторожевой процесс настолько близок, насколько вы можете получить гарантию (но кто-то может все же завершить обработку вашего сторожевого таймера).

...