2009-07-30 3 views
4

私が使用しているManualResetEventで少し混乱していますが、ブロックされていないようです。なぜこれが事実かもしれないのは誰でも知っていますか?ManualResetEvent WaitOneがブロック解除されていない

私が持っているシナリオは、これらの行に沿ったものです。実際の状況は非常に複雑で、問題を再現するために投稿するのに合理的なコードの部分を分離することはできませんでした。

編集
以下のコード例を更新しました。これは、いくつかの異なるダイアログで実行され、私はそれらのうちの1つがthis.mre.WaitOne()に当たることに気付きました。それでは、 "Switch to"または "再試行"を押す必要がある「サーバービジー」ダイアログが表示され、コードがWaitOne()呼び出しをパスしてすべてが動作するようになります。私はどのように関連性があるのか​​分かりませんが、明らかにその重要性があります。

public class A 
{ 
ManualResetEvent mre; 

public void Start(ThreadClass tc) 
{ 
    this.mre = new ManualResetEvent(false); 
    tc.Begin(); 

    WebClient wc = new WebClient(); 
    // progress events are pumped to the ThreadClass which then update the Form2. 
    wc.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(wc_DownloadFileCompleted); 

    wc.DownloadFileAsync("Src", "Tgt"); 
    this.mre.WaitOne(); 
} 

void void wc_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) 
{ 
    try 
    { 
    // Do Stuff 
    } 
    finally 
    { 
     this.mre.Set(); 
    } 
} 
} 

public class ThreadClass 
{ 
    Begin() 
    { 
     Thread t = new Thread(new ThreadStart(DoWork)); 
     t.Start(); 
    } 

    private void DoWork() 
    { 
    Form f = new Form2(); 
    f.ShowDialog(); 

    // Sits waiting on another ResetEvent to determine when to close the thread. 
    } 
} 
+0

'wc_DownloadFileCompeted'メソッドが呼び出されていますか? –

+0

ジョン、そうです。私はすぐに正常に実行されているSet()になっていますが、私のメインスレッドはまだブロックしています。 例が簡略化されていますが、Set()を別の場所で呼び出すと(たとえば、表示されるダイアログが表示され、キャンセルボタンにもイベントがあります)、このイベントにアタッチされたラムダのSet正常に動作します)。 – Ian

+0

divo、Set()は、WebClientが実際にファイルをダウンロードするために新しいWebClientを作成する必要があると仮定しているので、別のスレッドによって呼び出される可能性が最も高いでしょう。これは、WebClientがSet()を呼び出すイベントを送信するために使用するスレッドです。 – Ian

答えて

4

WebClientは呼び出し元と同じスレッドで実行されるため、スレッドはWaitOneでブロックされますが、実際には新しいスレッドは作成されません。

コードをBackgroundWorkerに移動するか、単純にブロックしないで、DownloadCompleteイベントが発生するのを待ちます。

+1

レイ、私はあなたに従うかどうかわからないのですか? DownloadFileAsync()を呼び出すスレッドは、ファイルがダウンロードされるまでブロックされている必要があります。 – Ian

+0

あなたのコードはすべて1つのスレッドで実行されています(確認するには、スレッドIDでデバッグトレースを入れてください)。つまり、同時に待機し、WebClientダウンロードを実行しようとしています。内部スケジューリングは、あなたが望むことを行うかもしれません。あるいは、あなたが得るようなエラーを得るかもしれません。待機する必要がある場合は、メソッドの非同期バージョン(暗黙の待機になる)を呼び出さないでください。または、真のマルチスレッドアプリケーションにしてください。 –

+0

私の例を若干更新しました。私は、UIイベントが処理されるかどうかは確かではありません。私はFormBが表示されるとき、彼らが新しく作成されたスレッドになることを期待します。 正直なところ、ResetEventがどのようにトリガーされていないのかわかりません。または私は何かを逃していますか? – Ian

1

なぜあなたはそれがとにかくブロックしたい場合は...代わりにwc.DownloadFileAsyncのあなたが設定しているMREは、実際にあなたが待っている同じMREであることを

+0

WebClientイベントは非同期でダウンロードする場合にのみ利用できるので、ダウンロード情報をユーザーに表示したいが、ファイルが開かれていることが確認できるまで、アプリケーションの進行状況をブロックしたい。 – Ian

+0

@Ianですが、あなたもGUIをブロックしています...ファイルがDownloadCompleteイベントで利用できることを知っているので、ポストWaitOneコードをイベントハンドラの中に移動してください! –

3

チェックをwc.DownloadFileを使用していません。これは簡単な例です - コードで2つの異なるリセットイベントを作成している可能性がありますか?それはかなり明らかに物を壊すだろう:)

+0

ジョン、MREは同じです。それ以前にチェックした。実際にコードを単純化できるかどうかを確認しようとしています。 – Ian

+0

コード構造体への更新を試みました。 Unfortuanetlyには、あらゆる種類のイベントやデリゲートを使って3/4クラスが含まれています。私はかなり簡単だと思っていますが、はるかに完全な例が必要です。 – Ian

2

私は少しあなたのコードを変更し、それは今までのように動作します。問題は、DownloadFileAsyncメソッドのユーザー状態パラメータとしてMREオブジェクトを渡す必要があります。

public class A 
{ 
public void Start(ThreadClass tc) 
{ 
    ManualResetEvent mre = new ManualResetEvent(false); 
    WebClient wc = new WebClient(); 
    // progress events are pumped to the ThreadClass which then update the Form2. 
    wc.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(wc_DownloadFileCompleted); 

    wc.DownloadFileAsync("Src", "Tgt", mre); 
    mre.WaitOne(); 
    mre.Close(); 
} 

void void wc_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) 
{ 
    try 
    { 
    // Do Stuff 
    } 
    finally 
    { 
     (e.UserState as ManualResetEvent).Set(); 
    } 
} 
} 
関連する問題