C#线程池QueueUserWorkItem异常处理

7
每当我的线程池中的一个线程抛出异常时,我的代码似乎会卡在线程函数内的 catch 块。我该如何将异常传回主线程?

重复:https://dev59.com/WHRA5IYBdhLWcg3w_DLF - Nick
1
可能是重复的问题:如何从ThreadPool.QueueUserWorkItem中捕获异常? - Henrik
好的,也许值得发布一些代码。这听起来像是您可能正在从非GUI线程访问GUI组件。 - Nick
我正在访问一个列表框,将异常添加到线程中。如果我直接抛出异常,它会卡在线程的 catch 块中,无法返回主线程。 - Aks
这个回答解决了你的问题吗?如何从ThreadPool.QueueUserWorkItem中捕获异常? - Michael Freidgeim
显示剩余4条评论
2个回答

7
最佳实践是您的后台线程不应抛出异常。让它们自己处理异常。
理想情况下,您应该在执行线程的方法中将代码包装在try-catch块中,并在catch块中处理异常。不要从catch块中重新抛出它。
阅读此内容以获取更多详细信息。http://www.albahari.com/threading/#_Exception_Handling 如果您想从后台线程更新UI,则可以使用Control.InvokeRequired属性和Control.Invoke方法。有关详细信息和示例,请参见MSDN链接。

但我的用户界面必须显示异常。我该怎么办? - Aks
1
在线程中捕获异常并使用队列(管道)向UI线程发送消息以显示错误。跨线程边界的异常是一件糟糕的事情,也很难排除故障。 - David Mårtensson

4

不可能直接将异常从一个线程传递到另一个线程。您可以构建一些同步机制,在线程之间传递异常信息,然后在目标线程中抛出新的异常,例如:

class Program
{
    Exception _savedException = null;
    AutoResetEvent _exceptionEvent = new AutoResetEvent(false);

    static void Main(string[] args)
    {
        Program program = new Program();
        program.RunMain();
    }

    void RunMain()
    {
        ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadMethod));

        while (true)
        {
            _exceptionEvent.WaitOne();
            if (_savedException != null)
            {
                throw _savedException;
            }
        }
    }

    void ThreadMethod(object contxt)
    {
        try
        {
            // do something that can throw an exception
        }
        catch (Exception ex)
        {
            _savedException = ex;
            _exceptionEvent.Set();
        }
    }
}

如果您有一个Win窗体应用程序,那么事情就简单得多了。在线程的catch子句中使用您窗体的Invoke(或BeginInvoke)方法,提供异常详细信息。在使用Invoke启动的方法中,您可以重新抛出或按照您想要的方式处理异常。


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