在.NET线程中捕获异常

7

在多线程应用程序中,如何发现Thread中发生了Exception并清理资源?否则,该线程可能仍然保留在内存中运行。

请注意,保留的HTML标签。

5个回答

5

正如Sean所说,你必须在线程方法内完成所有异常处理和清理工作,不能在线程初始化中完成。例如:

public void Run()
{
    try
    {
        Thread thread1 = new Thread(ThreadEntry1);
        thread1.Start();

        Thread thread2 = new Thread(ThreadEntry2);
        thread2.Start();
    }
    catch (NotImplementedException)
    {
        // Neither are caught here
        Console.WriteLine("Caught you");
    }
}

private void ThreadEntry1()
{
    throw new NotImplementedException("Oops");
}

private void ThreadEntry2()
{
    throw new NotImplementedException("Oops2");
}

相反,这种方法更加自包含,显然也能够工作:
public void Run()
{
    Thread thread1 = new Thread(ThreadEntry1);
    thread1.Start();
}

private void ThreadEntry1()
{
    try
    {
        throw new NotImplementedException("Oops");
    }
    catch (NotImplementedException)
    {
        Console.WriteLine("Ha! Caught you");
    }
}

如果你想知道线程是否失败,那么你应该考虑一个 WaitHandles 数组,并向调用方法发送信号。另一种更简单的方法是在每次线程操作完成时简单地增加计数器:
Interlocked.Increment(ref _mycounter);

2
如果你担心这种情况,那么应该在线程的入口点使用try/catch块,并显式进行清理。任何传递出线程入口点的异常都会导致应用程序关闭。

在 .Net 3.5 或以下版本中默认设置下无法捕获 ThreadAbortException,同时在 .Net 4.0 中也无法捕获可能表示已损坏状态的异常,同样是在默认设置下。 因此,使用默认设置下的 try catch 块无法捕获所有异常(也不建议这样做)。 - Pop Catalin
3
除非你中止线程,否则它不会引发ThreadAbortException异常- 你也可以捕获它们,但不要将它们吞下去,因为它们会自动重新抛出。 - Chris S
@Chris S,你说得对+1,我使用了“catching”这个词来表示“吞咽”,这是不正确的用法。 - Pop Catalin

1

你可以像处理普通函数一样捕获线程中的异常。 如果你的线程的“工作”函数被称为DoWork,那么可以这样做:

private void DoWork(...args...)
{
try
{
// Do my thread work here
}
catch (Exception ex)
{
}
}

1

A. 你有一个调用栈,可以在线程内部捕获它并将线程 ID 添加到日志中。

如果你以良好的方式包装线程,可以在 catch 部分添加清理代码,必要时终止线程。


同意。我不认为这是一个问题——你启动一个线程,它进入你的方法……那么有什么阻止你在那里处理异常呢? - TomTom

1
Eric Lippert最近发表了一篇关于工作线程中异常的不良影响的文章。值得一读并理解,异常是“异常”的,在工作线程中发生异常后,你唯一可以确定的是你不能再确定应用程序的状态。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接