スレッド内のメソッドが返されたにもかかわらず、Thread.Join()がハングするのはなぜですか?

私は、シングルスレッドアパートメントスレッドで実行する必要がある認証のためのいくつかのライブラリコードを使用する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オブジェクトに返すことができます。しかし、これらの詳細は、フリーズが単純化されたコードでさえも起こるので、私がフリーズに無関係に伝える限りです。]

4
@Guillaume:ブレークポイントは本当にヒットしました。スレッドは、ID 4492、管理ID 9、コードを実行するクラスと同じ位置(ClaimsAuthenticationModule)の名前のないワーカースレッドです。おそらくWPFに関連する7つのスレッドが実行されています。代わりにWPFビューのコンストラクタでコードを呼び出すときに問題が発生しないということに気付くかもしれません。 TextBox Validationコードから呼び出すと発生します。私はこれを回避策として使うことができると思うが、何が起こっているのかを知ることはいいだろう。 Jodrell:このテストケースではスレッドメソッドは何もしません。
追加された 著者 Geir Smestad,
@KooKiz:はい、これは間違いであることは間違いありません。私は作業コードで質問を更新し、簡略化の説明を加えました。この計画は分かりやすくするためのものでしたが、おそらくそれは逆効果でした。
追加された 著者 Geir Smestad,
スレッドのメソッドが完了したことを100%確信していますか?
追加された 著者 George Duckett,
スレッドメソッドは実際に何をしていますか?投稿されたコードに何か間違いはありませんか?
追加された 著者 Jodrell,
スレッドauthenticationThread =新しいスレッド(新しいThreadStart(threadMethod(authResult)));この行はどのようにコンパイルされますか?あなたのコードを貼り付ける際に間違いを犯しましたか?たぶんあなたの "本物の" threadMethodはvoidの代わりに何かを返しますか?
追加された 著者 Kevin Gosse,
debbugerを接続し、 'return'にブレークポイントを入れてみてください。あなたが本当にそれを打つかどうかを確認する。その場合は、どのスレッドをチェックしてください。
追加された 著者 Guillaume,

1 答え

あなたのコードに基づいて;あたかも正しく実行しているかのように見えますが、スレッドは決して本当に終了しません。スレッドの関数の最後にブレークポイントを設定してみてください。 returnキーワードの代わりに(あなたのreturnステートメントで何らかの処理を行っていて、スレッドが終了しないようにしている場合)、下の図に示すように ここに画像の説明を入力してください authenticationThread.Name(または例に示すmthread.Name)を使用してスレッドに名前を付けると、デバッグにも役立ちます。スレッドが本当に終了した場合は、「スレッド 'yourname'(0x143c)がコード0(0x0)で終了しました」と表示されるはずです。 Visual Studioの[出力]ウィンドウに表示されます。

7
追加された
スレッド名についてのヒントは+1です。スレッドメソッドの最後のブレースに配置されたブレークポイントは実際にヒットしますが、デバッガはそれをステップするときに「スレッドが終了しました」と報告しません。同じシナリオでは、コードがWPFではなく私によって呼び出されると、デバッガは<thread exit>を報告します。
追加された 著者 Geir Smestad,