如何检测主线程什么时候终止?

时间:2009-09-02 16:16:26

标签: c# .net multithreading logging

我需要知道的事情:

我想检测主线程(进程?)何时终止,以便我可以确保在终止之前执行某些操作。

我发现自己:

我找到了事件AppDomain.DomainUnloadAppDomain.ProcessExitAppDomain.DomainUnload似乎适用于非应用程序,如MbUnit。 AppDomain.ProcessExit似乎适用于应用程序,但有3秒的时间限制,我真的不喜欢。是否有更多方法可以检测AppDomain /进程何时终止?

背景:

我正在寻找这样的事件,以确保我的日志在应用程序终止时持久存档。实际的日志记录使用生产者 - 消费者模式在另一个线程上运行,其中日志条目很可能在内存中排队,我需要确保在应用程序终止时将此队列保存到文件中。

还有什么我应该注意的吗?

更新

更改了上述内容以反映我自己发现的内容。在ProcessExit期间,我对3秒的时间限制感到不满意。 MSDN文档确实说它可以扩展:

  

所有人的总执行时间   ProcessExit事件处理程序有限,   就像总的执行时间一样   所有终结者在过程中都是有限的   关掉。默认值为3   秒,可以被一个覆盖   非托管主机。

有谁知道如何覆盖默认值?

更多的想法也受到高度赞赏!

跟进:

I have posted a follow up question to this

5 个答案:

答案 0 :(得分:4)

您的应用程序应该有一个入口点。通常,当所有任务都终止时,您可以执行一些日志记录:

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

答案 1 :(得分:4)

你究竟想知道什么?

  • 当流程终止时? (仅仅因为卸载了AppDomain并不是必然意味着整个过程正在终止)
  • 当主线程终止时(如果有其他非后台线程,主线程可以在没有进程终止(或AppDomain卸载)的情况下终止)

所以他们不是一回事。

无论如何,将日志消息缓存在内存通常是危险的。如果有人关掉电源怎么办?或者,如果我通过任务管理器终止您的流程?您的所有日志消息都消失了。通常,您需要在日志中进行无缓冲写入,以便立即将消息推送到磁盘

无论如何,另一种(更强大的)方法可能是在非后台线程中运行记录器本身。这样,即使应用程序的其余部分终止,记录器也不会,因此进程保持活动状态。然后你只需要在应用程序的其余部分终止时设置一些标志,让记录器知道它一旦写出所有挂起的日志消息就应该关闭。

它仍然无法使您免于系统断电或有人在操作系统级别强制终止该过程的情况,但它将处理应用程序正常关闭的所有情况,并为您提供无限时间执行清理-up动作(因为该过程实际上还没有终止,它仍然有一个实时线程)

答案 2 :(得分:2)

  

即。保证被叫,有无限的时间完成?

不幸的是,NO选项将有无限的时间,并得到保证。没有办法强制执行此操作,因为很多事情都可能发生。有人绊倒电源线或强制终止你的程序将阻止任何选项给你足够的时间来处理事情。

通常,将您的逻辑放在Main例程的末尾可能是最合理的选项,因为这样可以让您完全自由地处理终止事件。你没有时间限制,可以根据需要花费很多时间。

不能保证这会运行,因为强行终止你的程序可能会完全绕过它。

答案 3 :(得分:0)

根据文档,看起来默认的应用程序域(您的Main方法可能正在运行的域)将不会收到DomainUnload事件。

我不知道内置事件会做你期望的事情。

您可以定义自己的custom event,让相关方注册,并在您从Main()返回之前触发事件。

答案 4 :(得分:0)

我不知道这个帖子多大了,但我遇到了类似的问题,这对我来说有点难以解决。

我有一个WinForms应用程序在用户注销时没有触发上述任何事件。尝试重写Application.Run()最终也无法正常工作。

现在要解决这个问题,你必须使用PInvoke进入Win32 API来实现这一目标。那么你还是在.NET 2.0之前做过。幸运的是,MS推出了一个名为SystemEvents的新类。使用此类,您可以捕获SessionEnd事件。此事件允许您在操作系统要终止您的应用程序时进行清理。它出现此事件没有.NET时间限制,但如果花费太长时间操作系统最终会终止您的应用程序。这有点超过3秒,虽然3秒应该有足够的时间进行清理。

其次我的另一个问题是我希望我的工作线程在完成其工作后终止主线程。使用Application.Run()这很难实现。我最终做的是使用共享的应用程序上下文调用Application.Run()。然后,该线程可以调用ApplicationContext.ThreadExit()来强制Application.Run返回。这看起来效果很好。

希望这有助于某人。

此致

NozFX