.NET - Финализаторы и выход (0) - PullRequest
2 голосов
/ 03 апреля 2009

У меня есть приложение .NET C # / C ++, которое использует вызов exit(0) (из <stdlib.h>) в потоке для завершения.

Странная часть заключается в том, что при некоторых обстоятельствах финализаторы управляемых объектов вызываются сразу после вызова exit, а в других случаях они вообще не вызываются.

Обстоятельства довольно детерминированы - приложение вызывает некоторые методы из внешнего плагина dll (написанного на неуправляемом C) в течение его жизни.
Если я использую dll A, финализаторы всегда вызываются.
Если я использую dll B, финализаторы никогда не вызываются.

Каково ожидаемое поведение финализаторов в случае вызова exit (0)? (если есть ожидаемое и документированное поведение)

Могут ли вызовы внешних библиотек изменить некоторые глобальные настройки, которые могут повлиять на способ завершения процесса?

Ответы [ 4 ]

3 голосов
/ 03 апреля 2009

Согласно книге Джеффа Рихтера, система пытается вызвать финализаторы при остановке процесса, но есть время для каждого финализатора (2 с) и полного завершения (40 с), охватывающее этот процесс, после чего процесс прерывается , (Конечно, к настоящему времени точное время могло измениться, это было правильно для 2.0)

Не видите ли вы финализатор, который запускается более 2 секунд? Это приведет к прекращению финализации.

3 голосов
/ 03 апреля 2009

Крис Брамм рассказал о том, как обрабатываются финализаторы во время остановки процесса:

Суть в том, что, похоже, очень мало гарантий для финализаторов, работающих при завершении работы, но я не уверен, что библиотеки DLL могут сделать, чтобы заставить вещи действовать по-другому (возможно, это тот самый DLL что-то делает при обработке DLL_PROCESS_DETACH, что дает .NET возможность обрабатывать финализаторы.

Статья предназначена для .NET 1.x - я не уверен, насколько это изменилось в .NET 2.0 или более поздней версии.

2 голосов
/ 03 апреля 2009

В конечном итоге это проблема "гонки вооружений". Кто-то регистрирует ошибку в Microsoft, жалуясь на то, что их финализаторы не работают, когда какой-то неприятный код завершает процесс - так что проблема исправлена. Затем кто-то другой регистрирует ошибку о том, что не существует способа заставить процесс завершиться немедленно, чтобы финализаторы не запускались, поэтому Microsoft добавляет новый API, чтобы разрешить это снова. Поэтому другому человеку требуется новый «критический» финализатор, который всегда работает даже в ответ на этот новый тип выхода ... и т. Д.

Так что, вероятно, было бы легче изменить код C ++, чем пытаться полагаться на то, кто в настоящее время выигрывает гонку вооружений.

1 голос
/ 11 апреля 2009

Если код, который вы вводите в финализаторы, довольно критичен, переместите его в Dispose и вызовите Dispose в ваших финализаторах с шаблоном if (! Disposed) в Dispose.

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

...