Распределить ресурсы по завершению процесса - PullRequest
6 голосов
/ 01 февраля 2009

Как я могу освободить ресурсы, когда процесс будет убит, например, диспетчером задач? Есть ли способ вызвать функцию до закрытия процесса?

Ответы [ 4 ]

8 голосов
/ 02 февраля 2009

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

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

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

Критическое завершение и структурированная обработка исключений не решат эту фундаментальную проблему.

С другой стороны, ОС освободит все ресурсы, о которых она знает, когда ваш процесс будет убит, а именно память и объекты ядра. Те не будут течь. Но исследователь не знает о вашем процессе, поэтому он не может очистить его.

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

4 голосов
/ 02 февраля 2009

Невозможно выполнить произвольный код после завершения в процессе, который собирается быть уничтожен вызовом TerminateProcess, например, из диспетчера задач, или другой утилитой процесса, такой как TSKILL или TASKKILL.

Ни критические финализаторы, ни обычные финализаторы, ни блоки try / finally, и, конечно, не просто объекты, которые реализуют IDisposable, не могут вызвать выполнение кода в этом сценарии. Даже события отключения DLL не будут вызываться из завершения процесса через TerminateProcess.

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

1 голос
/ 01 февраля 2009

Теоретически O / S должен освободить ресурсы после завершения процесса. О каком ресурсе вы думаете, в частности?


Edit:

Хорошо, это сложно объяснить. Я использую библиотеку, которая упаковывает некоторые функции ОС для управления некоторыми расширениями оболочки. Когда приложение закрывается без явного вызова соответствующих методов, все проводники зависают, и мне нужно перезапустить его.

Любая неуправляемая DLL должна (согласно документации) вызываться с событием DLL_PROCESS_DETACH; однако это DLL_PROCESS_DETACH событие не вызывается, когда процесс завершается через TerminateProcess API.

Погуглил по эти термины появился Старое новое: почему вы не можете перехватить TerminateProcess? который гласит: « Как только вы завершите работу с TerminateProcess, в этом процессе больше не будет работать код пользовательского режима. Он исчез. »

Поскольку все, с чем вы пытаетесь работать (например, .NET, Explorer, Shell, COM), происходит в пользовательском режиме, я думаю, что ответ заключается в том, что нет способа сделать то, что вы хотите.

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

0 голосов
/ 01 февраля 2009

Вы можете попробовать обернуть весь ваш процесс в оператор try / finally (вы помещаете материал освобождения в предложение finally), но в некоторых случаях даже этого будет недостаточно.

На самом деле, я думаю, что вы могли бы запустить фоновый поток из вашего процесса, чтобы выполнить всю работу и Thread.Join () с вашим основным потоком, так что если что-то пойдет не так в дочернем потоке, основной поток все еще сможет сделать все правильно. Конечно, это не будет работать, если весь процесс по какой-то причине будет прерван.

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

...