0

開始ボタンとキャンセル ボタンを備えた GUI インターフェイスがあります。開始後、GUI スレッドであるメイン スレッドは、実際の作業を行う 2 番目のスレッドを作成します。キャンセルボタンを押すと、作業スレッドに作業を停止して終了するように指示するブール値が設定されるだけです。問題は、作業スレッドが作業を終了したと確信しているにもかかわらず、メインの GUI スレッドがスタックしたままになることです。何故ですか?

コードの一部を次に示します。

    private Thread workerThread;
    private SomeClass fs;

    private void buttonSearch_Click(object sender, EventArgs e)
    {
      //do some initializations
      fs = new SomeClass();
      workerThread = new Thread(fs.WorkMethod);
      workerThread.Start();
    }

    private void buttonCancel_Click(object sender, EventArgs e)
    {
         fs.StopWork();
         workerThread.Join();
    }


    inside SomeClass:

    private bool keepWorking;

    public void StopWork()
    {
        keepWorking= false;
    }

    public void WorkMethod()
    {
       if (keepWorking)
        {
            //do some stuff with recursion
         }
    }

join を呼び出した後にメインスレッドが起動しない理由を誰かが知っていますか? keepWorking 変数を手動で false に変更し、メソッドが最後に到達した場合にどうなるかを確認するために、デバッグも試みました。

4

1 に答える 1

4

UIスレッドで実行するデリゲートを呼び出し、終了するまでブロックする呼び出しがありますWorkMethodInvokeUI スレッドは現在、バックグラウンド スレッドを待機する呼び出しをブロックしてJoinいるため、UI スレッドはそのデリゲートを呼び出すことができません。

両方のスレッドが互いに待機しており、進行していません。これを「デッドロック」と呼びます。

また、複数のスレッドからアクセスされていることをkeepWorking示す必要があります。volatile現状では、バックグラウンド スレッドは、メイン スレッドが変数を変更した後、かなりの時間、その変数の古い/キャッシュされた値にアクセスしている可能性があります。としてマークするとvolatile、ランタイムがそのような最適化を行うことができなくなります。

ここでの解決策は、 への呼び出しで UI スレッドをブロックしないことJoinです。バックグラウンド スレッドの終了時にコードを実行する必要がある場合は、同期的にブロックするのではなく、スレッドの終了時にそのコードを非同期的に起動する必要があります。

于 2013-05-24T17:28:09.113 に答える