代码之家  ›  专栏  ›  技术社区  ›  mcabral

如何知道谁杀了我的线

  •  28
  • mcabral  · 技术社区  · 15 年前

    我有一条线,它只是在驱赶..我想知道谁在杀我的线,为什么。

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

    至于线程,我可以断言它在死亡前至少有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();
    }
    

    编辑:寻址答案

    • 尝试/捕获可能的异常:
      它已经实现了,却什么也没有捕捉到:(
    • 主线染色:
      这个线程是由web服务器创建的,它将继续运行
    • 工作完成:
      这项工作还没有完成,因为它最终会影响数据库,所以我可以在线程死后检查它是否完成。

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

    还有,不是戈登特夫人拿着蜡烛棒在客厅里:)

    15 回复  |  直到 15 年前
        1
  •  20
  •   Community CDub    8 年前

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

    我建议您尝试关闭iis工作进程回收,看看这是否有区别。你可以找到更多的信息 here .

        2
  •  13
  •   John Saunders    15 年前

    你的线程可能只是抛出了一个异常。试着在周围放置一个try/catch块 DoSomethingForALongLongTime 看看有什么发现。


    更新: 我之前没注意到你是从网络服务器启动的。那可能是个非常糟糕的主意。特别是,单独的线程是否使用从 HttpContext.Current ?包括 Request , Response , Session 等等,以及页面上的任何信息。

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

    如果需要从web应用程序或web服务中启动一个长时间运行的线程,那么应该创建一个简单的windows服务并在其中托管一个wcf服务。让web页面将执行任务所需的所有信息发送给服务。服务甚至可以将msmq用作传输,这将确保即使服务很忙,也不会丢失任何消息。

        3
  •  5
  •   Chris Schmich    15 年前

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

    1. 下载 Debugging Tools for Windows 如果你还没有
    2. 运行windbg.exe,附加到进程
    3. 闯入Windbg,类型 sxe et 在线程退出时启用中断
    4. 当调试器中断时,检查系统、其他线程等的状态。
    5. 要获取托管堆栈,请加载sos.dll( .loadby sos mscorsvr , .loadby sos mscorwks .loadby sos clr 应该有效),然后运行 !clrstack (见 !help 对于其他SOS命令)

    如果从其他线程退出时收到大量噪音,则脚本windbg将在中断后继续(如果它不是您关心的线程id)。

    编辑: 如果您认为线程是从进程内终止的,也可以在 TerminateThread ( bp kernel32!TerminateThread ) ExitThread ( bp kernel32!ExitThread )去抓那一堆凶手。

        4
  •  4
  •   Andy Johnson    15 年前

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

    • 它会引发异常吗?你试过在doSomethingForaLongLongtime()调用周围放置try/catch吗?
    • 它有正常出口吗?试着在上面放些日志。
    • 调试器中和调试器中的行为是否相同?调试器中的输出窗口是否提供任何提示?

    更新

    你说:

    这个线程是由web创建的 服务器,继续运行

    如果线程在asp.net中运行,则可能是在asp.net工作进程循环使用时线程被终止,它将定期执行此操作。你可以尝试关闭工人流程回收,看看这是否有什么不同。

        5
  •  4
  •   Henk Holterman    15 年前

    你的编辑揭示了答案:

    这是 巴特勒 Web服务器。

    你到底是如何托管这些线程的?webserver环境并不是专门设计用来承载长时间存在的进程的。事实上,它可能配置为停止失控的站点,每40分钟一次?

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

    另一方面,在asp.net应用程序中使用backgroundworker没有什么意义,它是为winforms和wpf设计的。最好为此创建一个单独的线程,因为您正在更改一些线程属性。对于threadpool(bgw)线程不建议这样做。

        6
  •  3
  •   Jimmy    15 年前

    进程可能正在终止。这就是worker.isbackground=true;的目的,在主线程退出时终止线程。

        7
  •  3
  •   Alfred Myers    15 年前

    后台线程只在前台线程运行时运行。

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

        8
  •  2
  •   ChrisF    15 年前

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

        9
  •  2
  •   Jeroen Landheer    15 年前

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

    • 如果您的线程托管在IIS中,则该线程可能会被回收的应用程序池进程终止。服务器可能会继续运行,但承载项目的进程将停止,直到再次触发新请求。
    • 如果您的线程托管在可执行文件中,唯一可以终止它的方法是您自己终止线程,在线程中引发异常或终止主机进程

    希望这有帮助。

        10
  •  2
  •   Oleg    15 年前

    你可以试着增加 执行超时 价值 配置\系统.web\httpruntime 在里面 Web.CONFIG (默认值在.NET 4.0中为110秒,在.NET 4.0中为90秒,对应于 http://msdn.microsoft.com/en-us/library/e1f13641.aspx )您可以尝试动态更改它server.scriptTimeout=300(请参见 http://www.beansoftware.com/ASP.NET-Tutorials/Long-Operations.aspx )如果这个参数不起作用,那么我认为您在从iis回收线程时会遇到其他问题。如何查看此参数的默认值远不如线程的典型实时性。我认为,你的问题有另一个性质,但可以肯定的是…

    为什么要为线程设置公寓状态?在工作线程中使用哪些COM对象?您是否有一个非托管代码,它可以在您还可以插入一些代码的地方完成大部分工作?我想你应该有更多关于 SomethingForALongLongTime 才能解决问题。

    还有一个小小的建议。你能在调用后插入一行代码吗 SomethingForALongLongTime(); 可以肯定的是 一些长期的事情 没有例外的结局?

    更新:为了确保您的线程不会被IIS杀死,您可以尝试创建一个进程 一些长时间的事情; 而不是使用线程。

        11
  •  2
  •   Justin    15 年前

    调用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);
     }
    }
    
        12
  •  1
  •   Ian Mercer    15 年前

    可能是扔了一个 不可修补的异常 包括 堆栈溢出 内存不足 . 这些是最难找到的例外。

    当这个线程运行时,内存消耗是什么样子的?你能用一个内存分析器来检查它是否失控吗?你能在内部循环中添加一些日志吗?如果有递归方法,则添加一个计数器,并在其递归次数不可能达到的情况下引发异常。您是否使用了可能导致大型对象堆碎片的大型对象(即使您不是真的用完了,也会导致内存不足错误)。

        13
  •  1
  •   Chris O    15 年前

    您应该在dosomethingforalonglongtime()中插入大量调试日志,这样您就可以知道代码在什么地方停止执行。或者附加一个调试器并在所有第一次出现异常时中断。

        14
  •  1
  •   Tim Mahy    15 年前

    使用异步任务在asp.net中实现长时间运行的工作

        15
  •  1
  •   Kamarey    15 年前

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

    如果你错过了一些例外情况,它可能会给你一些信息

    推荐文章