2009-09-02 2 views
3

Что мне нужно знать:Как определить, когда основной поток завершается?

Я хотел бы, чтобы определить, когда основной поток (процесс?) Обрывается, так что я могу обеспечить определенные действия выполняются до того, как прекращается.

То, что я нашел себя:

Я нашел событий AppDomain.DomainUnload и AppDomain.ProcessExit. AppDomain.DomainUnload, похоже, работает с не-приложениями, такими как MbUnit. AppDomain.ProcessExit, похоже, работает с приложениями, но есть 3-секундный лимит времени, который мне действительно не нравится. Есть ли способ обнаружить, когда AppDomain/процесс завершается?

фон:

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

Есть ли что-нибудь еще, о чем я должен знать?

Update:

Изменено выше, чтобы отразить то, что я узнал сам. Я не доволен 3-секундным лимитом во время ProcessExit. В документации MSDN действительно говорит, однако, что он может быть продлен:

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

Кто-нибудь знает, как переопределить значение по умолчанию?

Другие идеи также высоко ценятся!

Развейте:

I have posted a follow up question to this.

ответ

0

На основании документации это похоже на домен приложения по умолчанию (тот, который, вероятно, работает в основном методе), не получит событие DomainUnload.

Я не знаю встроенного события, которое будет делать то, что вы ожидаете.

Вы можете указать свой собственный custom event, если заинтересованные стороны зарегистрировались у него и прекратили мероприятие непосредственно перед возвратом из Main().

+0

Звуки своего рода Hacky :-). Надеюсь, что есть лучшее решение. Спасибо за идею, хотя! – 2009-09-02 16:23:55

+0

Кстати, вы были правы о Domain.Unload, не работающем в приложении. Черт. – 2009-09-02 16:27:10

+0

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

4

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

static void Main() 
{ 
    try 
    { 
    Application.Run(....); 
    } 
    finally 
    { 
    // logging ... 
    } 
} 
4

Что именно вы хотите узнать?

  • Когда процесс завершается? (Только потому, что AppDomain разгружен, не обязательно означает, что весь процесс завершается)
  • Когда основной поток завершается (если есть другие нефонические потоки, основной поток может завершиться без завершения процесса (или AppDomain разгрузка)

Так они не совсем то же самое.

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

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

Он по-прежнему не спасет вас от случая, когда система теряет власть, или кто-то насильственно связывает процесс на уровне ОС, но он будет обрабатывать все случаи, когда приложение закрывается нормально, и дает вам неограниченное время для выполнения (поскольку процесс еще не завершен, у него все еще есть одна живая нить)

+0

Это очень хороший вопрос о том, что поток журналов не заканчивается, если это не поток BG. –

+0

Спасибо за разъяснение. Производительность имеет решающее значение, и именно поэтому я решил буферизовать сообщения журнала в памяти, но потерять все из-за перебоев в подаче электроэнергии сильно засасывает. Логгер работает в фоновом потоке прямо сейчас. Я не знал/не заметил, что это задержит процесс. Считаете ли вы, что реализация IDisposable будет хорошей идеей? Я предполагаю, что основная проблема заключается в том, что я действительно не понимаю разницу между AppDomain и процессом и что заставляет их прекращать работу. Мне нужно это изучить. Спасибо за ваш подробный ответ! – 2009-09-02 16:34:56

+0

+1 для идеи потока переднего плана (т. Е. Не-фона). Каждый поток, созданный через Thread.Start(), является потоком переднего плана по умолчанию, тогда как потоки в ThreadPool являются строго фоновыми потоками. –

2

т.е. гарантировано быть вызванным и иметь неограниченное время, чтобы закончить?

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

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

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

+1

Черт, я ненавижу, что ты не можешь контролировать реальность :-). – 2009-09-02 17:35:26

0

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

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

Теперь, чтобы обойти это, вам нужно будет использовать PInvoke в API Win32 для достижения этого. Хорошо, что вы делали до .NET 2.0 в любом случае. Luckly MS представила новый класс под названием SystemEvents. С помощью этого класса вы можете поймать событие SessionEnd. Это событие позволяет вам очищать, когда ОС хочет завершить работу вашего приложения. Здесь нет .NET время o это событие появляется, хотя ОС в конечном итоге уничтожит ваше приложение, если вы займете слишком много времени. Это немного больше 3 секунд, хотя 3 секунды должно быть достаточно времени для очистки.

Во-вторых, моя другая проблема заключалась в том, что я хотел, чтобы мой рабочий поток завершил основной поток, как только он завершил свою работу. С Application.Run() этого было трудно достичь. То, что я закончил, было вызвано Application.Run() с общим контекстом приложения. Затем поток может вызвать ApplicationContext.ThreadExit(), чтобы принудительно вернуть Application.Run. Кажется, это работает очень хорошо.

Надеюсь, это поможет кому-то.

С уважением

NozFX

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