DOBON.NET DOBON.NETプログラミング掲示板過去ログ

Threadオブジェクトでスレッドを作成し、Joinするとフリーズする現象について。

環境/言語:[WindowsXP, C#]
分類:[.NET]

こんにちは。

Threadクラスを使用して起動したスレッドからFormクラスの関数をdelegate呼び出
しし、起動したスレッドオブジェクトに対してJoin()を呼び出すと「フリーズ」
してしまうという現象があるようです。
(ちなみに、呼び出し先スレッドからFormクラスの関数を(delegateではなく)直接
呼び出すとO.K.でしたが...)

この現象にお詳しい方がいらっしゃいましたらご助言をお願いします。

以下のソースは、Formクラスが、ファイルを検索するスレッドを別スレッドとして
作成し、そのスレッド側でFormクラスの関数をdelegate呼び出し、作成したスレッ
ドオブジェクトに対してJoinを使用した例をモデル化して記述してあります。

--------------------------------------------------------------------------
  public partial class Form1 : Form
  {
    public void OnRegisterFile( string filePath );
    public delegate void delRegisterFile( string filePath );
    
    /*中略*/
    
    public void OnRegisterFile( string filePath )
    {
      // 検索されたファイルをリストボックスに追加する処理 
    }
    
    // ボタンクリック
    private void btnFile_Click ( object sender , EventArgs e )
    {
      Thread th = new Thread( new ThreadStart( FileFindFunc ) );
      th.Start();
      
      th.Join(); // 終わるまで待つ。
    }
    
    // ファイル検索スレッド関数
    private void FileFindFunc()
    {
      FileFind ff = new FileFind( this );
      ff.Find();
    }
  }
  
  // ファイル検索クラス
  public class FileFind
  {
    // デリゲート型宣言
    private delegate void delRegisterFile( string filePath );
    // 親フォーム
    private Form1 mMainFrm;
    // デリゲート
    private delRegisterFile mRegisterFile;
    
    // コンストラクタ
    public FileFind( Form1 frm )
    {
      mMainFrm   = frm;
      mRegisterFile = new delRegisterFile(mMainFrm.OnRegisterFile);
    }
    
    // 検索処理
    public void Find()
    {
      while(/* 何らかの条件 */)
      {
        string filePath; // ファイルパス
        
        /* 中略 */
        
        // ファイルが見つかった(Form1クラスのOnRegisterFileをdelegateで呼び出す。)
        mMainFrm.Invoke( mRegisterFile, filePath );
        
      }
    }
  }
--------------------------------------------------------------------------
お疲れ様です。
デッドロックしています。

>         // ファイルが見つかった(Form1クラスのOnRegisterFileをdelegateで呼び出す。)
>         mMainFrm.Invoke( mRegisterFile, filePath );
>         

mMainFrm.Invokeを使っているので、
OnRegisterFileメソッドは、
mMainFrmを作成したスレッド(btnFile_Clickを実行しているスレッド)上で実行されます。
mMainFrmを作成したスレッドは、btnFile_Clickメソッドが終了した後、
OnRegisterFileメソッドを呼び出します。
しかし、

>     // ボタンクリック
>     private void btnFile_Click ( object sender , EventArgs e )
>     {
>       Thread th = new Thread( new ThreadStart( FileFindFunc ) );
>       th.Start();
>       
>       th.Join(); // 終わるまで待つ。
>     }

th.Join()しているので、
btnFile_Clickメソッドは、FileFind.Find()メソッドが終わるまで待ちます。
一方、FileFind.Find()メソッドは、mMainFrm.Invokeを使っているので、
OnRegisterFileメソッドの実行が終わるまで待機します。
前述のように、OnRegisterFileメソッドは、btnFile_Clickメソッドが終わるまで実行されません。

すなわち、お互いが永久に相手の終了を待ち続けている状態です。
ありがとうございました。
とても分かりやすい説明ありがとうございました。


■No26171に返信(H.K.R.さんの記事)
> お疲れ様です。
> デッドロックしています。
> 
>>        // ファイルが見つかった(Form1クラスのOnRegisterFileをdelegateで呼び出す。)
>>        mMainFrm.Invoke( mRegisterFile, filePath );
>>        
> 
> mMainFrm.Invokeを使っているので、
> OnRegisterFileメソッドは、
> mMainFrmを作成したスレッド(btnFile_Clickを実行しているスレッド)上で実行されます。
> mMainFrmを作成したスレッドは、btnFile_Clickメソッドが終了した後、
> OnRegisterFileメソッドを呼び出します。
> しかし、
> 
>>    // ボタンクリック
>>    private void btnFile_Click ( object sender , EventArgs e )
>>    {
>>      Thread th = new Thread( new ThreadStart( FileFindFunc ) );
>>      th.Start();
>>      
>>      th.Join(); // 終わるまで待つ。
>>    }
> 
> th.Join()しているので、
> btnFile_Clickメソッドは、FileFind.Find()メソッドが終わるまで待ちます。
> 一方、FileFind.Find()メソッドは、mMainFrm.Invokeを使っているので、
> OnRegisterFileメソッドの実行が終わるまで待機します。
> 前述のように、OnRegisterFileメソッドは、btnFile_Clickメソッドが終わるまで実行されません。
> 
> すなわち、お互いが永久に相手の終了を待ち続けている状態です。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板