2009-07-24 2 views
6

У меня есть консольный режим, который использует SQLite3 для ведения файла базы данных. Требуется некоторое время для выполнения, но в любой момент должно быть безопасно отменять, предполагая, что происходит запись базы данных. (Это все под Windows)TerminateProcess vs Ctrl + C

Это безопаснее, с точки выполнения программы, чтобы ударить CtrlC в консоли, чем иметь другой TerminateProcess вызова программы на нем?

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

Обратите внимание, что программа фактически не обрабатывает сигнал (если только SQLite не делает); Я говорю о встроенных механизмах по умолчанию для исполняемых файлов Win32 для обработки CtrlC сигнал.

Для уточнения/упрощения Вопрос-, учитывая, что это запись только выполняется:

fwrite(buf, 1024*1024, 1, stream); 

Во время этой записи, будет TerminateProcess вести себя иначе CtrlC?

ответ

5

Все это неотразимые аргументы, но единственный способ узнать наверняка - попробовать его. Поэтому я написал простую программу, которая выделяет буфер 1 ГБ, присваивает ему некоторые данные, а затем записывает их в файл, используя один файл fwrite().Я попробовал несколько способов, чтобы получить запись в «коррумпированные» данные (я ожидающей усеченный файл, в частности):

  • Вызов TerminateProcess (с помощью функции глушения PERL и Win32 :: Process :: убийствам)
  • Нажатие CtrlC
  • Использование "Завершить процесс" диспетчера задач
  • Использование процесса "Kill Process" Проводника

Ничто не остановило бы запись в каждом случае, файл был правильного размера и имел правильные данные. И хотя «Убийство» произойдет мгновенно, процесс будет задерживаться до тех пор, пока запись не завершится.

Кажется убедительным, что нет никакой разницы между TerminateProcess и CtrlC от точки ввода/вывода view- как только начинается запись, кажется, гарантированно завершить (за исключением отключения электроэнергии).

+0

Очень интересно, я полагаю, что операция ввода-вывода завершается независимо, так как просто не имеет смысла ее останавливать, что бы она могла сделать, кроме как привести к коррупции. Должен быть другой способ блокировки TerminateProcess, скрытый где-то. Интересный материал. Благодарю. – Gavin

+1

Я подозреваю, что TerminateProcess не может безопасно убить процесс во время выполнения syscall: контекст потока на этом этапе находится в пространстве ядра, и принудительное его уничтожение может привести к утечке системных ресурсов. OS, возможно, устанавливает крючки для всех потоков процесса, выполняемых в настоящее время в пространстве ядра, которые убивают поток, когда он пытается вернуться из системного вызова. – pmdj

0

SQLite утверждает, что является атомарным, даже во время сбоев питания, см. http://www.sqlite.org/atomiccommit.html.

Единственным исключением является то, что некоторые дисковые системы сообщают, что запись произошла успешно до того, как данные фактически записаны на дисковые планшеты, то есть данные находятся в кэш-памяти диска, или операционная система лежит на SQLite. См. http://www.sqlite.org/lockingv3.html, раздел 6.0. Как повреждать файлы базы данных.

Процессы, которые прекращаются must stop all running threads and complete pending I/O operations before they exit. Целостность данных должна быть гарантирована при условии, что процесс не разбился.

+0

«Единственное отличие в этом отношении от Ctrl-C и TerminateProcess - это то, как приложение было написано для обработки любого из этих событий». Является ли это догадкой или у вас есть доказательства, подтверждающие это? – arolson101

+0

Ссылка, которую дал Мануэль, кажется авторитетной. По-видимому, я сделал неправильное предположение о прекращении; он должен находиться в ожидании ввода-вывода, который удерживает задачу открытой, а не программист, перехватывающий завершающий вызов. Я отредактировал свой ответ, чтобы отразить это. –

1

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

TerminateProcess - это скорее удар в зубах, приложение не может справиться с этим, оно исходит из ядра, и если приложение сможет его обработать, это создаст всевозможные проблемы с «un killable» процессами, зависящими от TerminateProcess обработчика и отказа от выхода.

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

Отличный код проекта статьи здесь на обработку окна консоли сигналы:

http://www.codeproject.com/KB/winsdk/console_event_handling.aspx

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

Вы можете заблокировать TerminateProcess, но его «не очень« вежливое »программирование, это больше похоже на программирование корневого набора, я видел хорошую статью на этом в rootkit.com, поэтому ищите там« Invincability процесса », непобедимый процесс, он мог в свое время отключиться после получения такого «запроса» и выполнить любую очистку до hnad, но это, безусловно, взломать.

Мне кажется, однако, что CtrlC поведение вы сейчас видите, это из-за его не сразу окончание запущенного процесса.

0

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

TerminateProcess принудительно завершает процесс и любые дочерние потоки.

От MSDN:

TerminateProcess Функция Завершает указанного процесса и всех его нитей. ... Примечания

Функция TerminateProcess используется , чтобы безоговорочно вызвать процесс до выхода . Состояние глобальных данных , поддерживаемых библиотеками динамической компоновки (DLL) может быть скомпрометировано, если используется TerminateProcess, а не ExitProcess.

TerminateProcess инициирует завершение и немедленно возвращается. Это останавливает выполнение всех потоков в рамках процесса и требует отмены всех ожидающих ввода-вывода. Прекращенный процесс не может выйти до завершения или отмены всех ожидающих ввода-вывода.

Невозможно предотвратить процесс от .

Есть способы для процесса блокировки TerminateProcess, но я сомневаюсь, что SQLite3 сделает это.

+0

В вашей статье говорится, что нет никакой разницы, но вы говорите, что безопаснее использовать CTRL + C. Помните, мы говорим о программе, специально не написанной для обработки сигналов. Есть ли причина, по которой вы говорите, что безопаснее использовать CTRL + C? – arolson101

+0

CTRL + C не будет принудительно завершать процесс и дочерние потоки, он просто скажет ему об отключении. Если он не обрабатывается, он просто выходит. TerminateProcess может вызвать глобальное повреждение данных, поскольку он говорит о MSDN. В своем решении вы заявляете, что ничто не остановит запись; это потому, что даже TerminateProcess не закончит его, если есть I/O («Прекращенный процесс не может выйти, пока все ожидающие ввода-вывода не будут завершены или отменены».). Это было и в MSDN. – Manuel

Смежные вопросы