【问题标题】:Why does Thread.Join() hang even though the methods in the thread have returned?即使线程中的方法已经返回,为什么 Thread.Join() 会挂起?
【发布时间】:2011-11-25 08:44:38
【问题描述】:

我有一个 WPF 应用程序,它使用一些库代码进行身份验证,需要在单线程单元线程中运行。我的方法是生成一个单独的线程来获取身份验证对象,阻塞直到线程返回,然后继续执行。然而,在 一些 实例中,我的应用程序在 Thread.Join() 上挂起,即使线程方法已返回。

    public static ClaimsAuthenticationResult GetClientContextAndCookieCollection(string siteUrl, out CookieCollection cookieResult)
    {
        ClaimsAuthenticationResult authResult = new ClaimsAuthenticationResult();

        // Authentication module needs to run in single-thread apartment state because it uses
        // COM library calls where this is required
        Thread authenticationThread = new Thread(new ThreadStart(threadMethod));
        authenticationThread.SetApartmentState(ApartmentState.STA);
        authenticationThread.Start();

        // Block until thread completion
        authenticationThread.Join(); // Application hangs here

        return authResult;
    }

    private static void threadMethod() {
        // In proper application: set result. But for debugging, return immediately
        return;
    }

我是多线程和 WPF 的新手,所以我可能会做一些愚蠢的事情。有人看到这里发生了什么吗?作为记录,如果我不将线程设置为 STA,我不会遇到问题,但这是一个要求。

[编辑:似乎只有当我通过 WPF 视图中的验证绑定调用指定的方法时才会发生错误,特别是在 TextBox 上。当我在视图的构造函数中调用相同的代码时,代码会按预期运行。这将是一个可行的解决方法,但了解这里实际发生的情况会很有趣。]

[编辑:这里的代码已经被简化了一点调试 - 在生产代码中,线程方法位于 AuthThreadWorker 对象中,该对象可以将身份验证过程的结果返回给 authResult 对象。但据我所知,这些细节与冻结无关,因为即使在简化代码中也会发生冻结。]

【问题讨论】:

  • 你确定线程的方法已经完成了吗?
  • 尝试附加调试器并在“return;”上设置断点检查你是否真的击中它。如果是,请检查哪个线程。
  • 线程方法实际上是做什么的,我没有看到发布的代码有什么问题?
  • @Guillaume:断点确实被命中。线程是一个未命名的工作线程,ID 为 4492,托管 ID 为 9,位置与运行代码的类 (ClaimsAuthenticationModule) 相同。有 7 个线程在运行,大概是 WPF 相关的。可能值得注意的是,当我改为在需要它的 WPF 视图的构造函数中调用代码时,问题确实 not 发生。当我从 TextBox Validation 代码中调用它时,它确实会发生。我想我可以将其用作解决方法,但很高兴知道发生了什么。 Jodrell:线程方法在这个测试用例中什么都不做。
  • 线程认证Thread = new Thread(new ThreadStart(threadMethod(authResult)));这条线是如何编译的?您在粘贴代码时是否犯了错误?也许你的“真实” threadMethod 返回一些东西而不是 void?

标签: c# wpf multithreading


【解决方案1】:

根据您的代码;看起来好像你做对了,但线程永远不会真正终止。尝试在线程中函数的END处设置断点;而不是 return 关键字(如果您在 return 语句中进行某种处理以防止线程退出),如下图所示 。使用 authenticationThread.Name(或示例中所示的 mthread.Name)命名线程也有助于调试。如果线程真的终止了,你应该看到“线程'你的名字'(0x143c)已经退出,代码为0(0x0)。”在 Visual Studio 的输出窗口中。

【讨论】:

  • +1 获取有关线程名称的提示。放置在线程方法最后一个大括号上的断点确实被命中,但调试器在跳过它时不会报告“线程退出”。在同样的场景中,当我调用代码而不是 WPF 时,调试器 确实 报告“线程已退出”。
  • 既然你提到了WPF,你可能会间接调用'onpropertychanged',因为你设置了一些属性值。在这种情况下,changenotification 将等待 UI 线程,反之亦然。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-12
相关资源
最近更新 更多