28

我有一个正在放逐的线程..我想知道谁在杀死我的线程以及为什么。

我突然想到我的线程被操作系统杀死了,但我想确认一下,如果可能的话,我想知道它为什么会杀死它。

至于线程,我可以断言它在死亡前至少有 40 分钟的执行时间,但它在 5 分钟左右突然死亡。

public void RunWorker()
{
    Thread worker = new Thread(delegate()
    {
        try
        {
            DoSomethingForALongLongTime();
        }
        catch(Exception e)
        {
           //Nothing is never logged :(
           LogException(e);
           throw e;
        }
    });

    worker.IsBackground = true;
    worker.SetApartmentState(System.Threading.ApartmentState.STA);
    worker.Start();
}

编辑:解决答案

  • Try/Catch 可能的异常:
    它已实现但什么也没捕获 :(
  • 主线程消亡:
    该线程由网络服务器创建,继续运行
  • 工作完成:
    工作没有完成,因为它最终影响到数据库,我可以在线程死亡时检查它是否完成。

想到这些,我想到了这个问题,谁在扼杀我的线程??

附言。不是客厅里拿着烛台的戈登夫人 :)

4

15 回答 15

20

很多人(包括我自己,在这里)指出在 IIS 中托管一个长时间运行的线程是一个坏主意。您的线程将在 IIS“工作进程”中运行。IIS 会定期终止(回收)这些进程,这将导致您的线程终止。

我建议您尝试关闭 IIS 工作进程回收,看看是否有影响。您可以在此处找到更多信息。

于 2010-05-12T10:01:04.120 回答
13

您的线程可能只是抛出了一个异常。尝试在周围放置一个 try/catch 块DoSomethingForALongLongTime,看看它会拾取什么。


更新:我之前没有注意到您是从 Web 服务器启动的。这可能是一个非常糟糕的主意。特别是,单独的线程是否使用从 ? 派生的任何信息HttpContext.Current?这将包括RequestResponseSession等,以及来自页面的任何信息。

这很糟糕,因为这些事情只会持续到请求持续的时间。一旦请求结束,它们就会变得无效,至少可以这么说。

如果您需要从 Web 应用程序或 Web 服务中启动一个长时间运行的线程,那么您应该创建一个简单的 Windows 服务并在其中托管一个 WCF 服务。然后让网页将执行任务所需的所有信息发送到服务。该服务甚至可以使用 MSMQ 作为传输,这将确保不会丢失任何消息,即使服务繁忙。

于 2010-04-20T14:28:52.190 回答
5

获取更多信息的一种潜在方法:附加调试器并在线程终止时中断。根据您的线程被终止的方式,这可能不起作用。

  1. 如果您还没有Windows 调试工具,请下载它
  2. 运行windbg.exe,附加到你的进程
  3. 进入windbg,键入sxe et以启用在线程退出时中断
  4. 当调试器中断时,检查系统、其他线程等的状态。
  5. 要获取托管堆栈,请加载 sos.dll(.loadby sos mscorsvr.loadby sos mscorwks.loadby sos clr应该可以工作),然后运行!clrstack(参见!help其他 sos 命令)

如果您从其他线程退出中得到很多噪音,如果它不是您关心的线程 ID,则脚本 windbg 在中断后继续。

编辑:如果您认为线程正在从您的进程中终止,您还可以在TerminateThread( bp kernel32!TerminateThread) 和ExitThread( bp kernel32!ExitThread) 上设置断点以捕获杀手的堆栈。

于 2010-05-07T02:14:27.627 回答
4

我不知道答案,但有一些想法:

  • 会不会抛出异常?您是否尝试过在 DoSomethingForALongLongTime() 调用中使用 try/catch?
  • 有没有正常退出的点?尝试对它们进行一些日志记录。
  • 您是否在调试器中获得相同的行为?调试器中的输出窗口是否提供任何提示?

更新

你说:

该线程由 Web 服务器创建,并继续运行

如果线程在 asp.net 中运行,那么当 asp.net 工作进程回收时,线程可能会被杀死,它会定期执行此操作。您可以尝试关闭工作进程回收,看看是否有什么不同。

于 2010-04-20T14:31:58.673 回答
4

您的编辑揭示了答案:

它是管家网络服务器。

您究竟如何托管这些线程?网络服务器环境并不是专门为托管长期存在的进程而设计的。事实上,它可能被配置为每 40 分钟停止一次失控的站点?

编辑:
为了快速修复,您最好的机会是设置worker.IsBackground = false;,因为您当前的设置 true 允许系统在不等待您的 bgw 的情况下杀死父线程。

另一方面,在 ASP.NET 应用程序中使用 BackgroundWorker 没有什么意义,它适用于 WinForms 和 WPF。最好为此创建一个单独的线程,因为您正在更改一些线程属性。对于 ThreadPool (Bgw) 线程,不建议这样做。

于 2010-04-20T14:45:14.533 回答
3

该过程可能正在终止。那就是worker.IsBackground = true; 旨在做,当主线程退出时杀死你的线程。

于 2010-04-20T14:30:24.683 回答
3

只要有前台线程运行,后台线程就会运行。

一旦所有前台线程结束,任何仍在运行的后台线程都将中止。

于 2010-04-20T14:30:49.277 回答
2

如果检查异常没有显示任何有用的信息,请让您的线程代码在关键点写入日志文件。然后,您将能够准确地看到它何时停止工作,并希望看到原因。

于 2010-04-20T14:30:28.023 回答
2

一个简单的答案是:“凶手没有留下名片”;)

  • 如果您的线程托管在 IIS 中,则该线程可能被回收的应用程序池进程杀死。服务器可能会继续运行,但托管您的项目的进程会停止,直到新的请求再次启动所有内容。
  • 如果您的线程托管在可执行文件中,则可以杀死它的唯一方法是自己杀死线程,在线程中抛出异常或终止宿主进程

希望这可以帮助。

于 2010-04-20T15:28:51.273 回答
2

您可以尝试增加web.config中configuration\system.web\httpRuntimeexecutionTimeout值(默认值在 .NET 4.0 中为 110 秒,在http://msdn.microsoft.com/en-us/library/中为 90 秒e1f13641.aspx)。您可以尝试动态更改它 Server.ScriptTimeout = 300 (请参阅http://www.beansoftware.com/ASP.NET-Tutorials/Long-Operations.aspx)。如果此参数无济于事,那么我认为您还有其他问题,例如从 IIS 回收线程。您如何查看此参数的默认值与线程的典型生存时间相比要少得多。我认为,您的问题具有另一种性质,但可以肯定的是......

为什么要为线程设置单元状态?您在工作线程中使用了哪些 COM 对象?您是否有一个非托管代码可以完成大部分工作,您还可以在其中插入一些代码?我认为您应该了解更多有关SomethingForALongLongTime能够解决问题的信息。

还有一个小建议。您能否在调用后插入一行代码SomethingForALongLongTime();以确保SomethingForALongLongTime不会无异常结束?

更新:为了绝对确保您的线程不会被 IIS 杀死,您可以尝试创建一个进程来SomethingForALongLongTime();代替使用线程。

于 2010-05-05T23:52:35.947 回答
2

当您调用 RunWorker() 时,您可以将对线程的引用添加到列表中。一旦你检测到你的线程已经死亡,你可以检查线程的状态,也许它会揭示它是如何死亡的。或者,也许它还没有死,它只是在等待一些资源(比如与数据库的连接)。

List runningThreads = ...
public void RunWorker() {
    Thread worker = new Thread(delegate()
    ..
    runningThreads.add(worker);
    worker.Start();
}

public void checkThreads() {
 for (Thread t : runningThreads) {
   Console.WriteLine("ThreadState: {0}", t.ThreadState);
 }
}
于 2010-05-11T20:12:06.783 回答
1

它可能会引发各种无法捕获的异常之一,包括Stack OverflowOut of Memory。这些是最难追踪的例外情况。

此线程运行时内存消耗情况如何?你可以使用内存分析器来查看它是否失控吗?您可以在内部循环中添加一些日志记录吗?如果您有递归方法,请添加一个计数器,如果递归次数不可能,则抛出异常。您是否使用可能导致大对象堆碎片的大对象(即使您并没有真正出问题也会导致内存不足错误)。

于 2010-05-06T00:07:19.010 回答
1

您应该使用大量调试日志来检测 DoSomethingForALongLongTime(),这样您就可以找出代码在什么位置停止执行。或者附加一个调试器并中断所有第一次机会异常。

于 2010-05-07T02:27:06.707 回答
1

使用 AsyncTasks 实现您在 asp.net 中长期运行的工作

于 2010-05-11T20:14:38.120 回答
1

尝试使用应用程序域 UnhandledException 事件:http: //msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx

如果您错过一些例外情况,它可能会为您提供一些信息

于 2010-05-12T10:20:18.860 回答