2009-05-11 21 views
2

私はクラスライブラリに次のコードを書いています。私は主なアプリケーションにコールバックを待つ。私はそれが完了した後にコールバックを取得するために数秒待つ必要があるので、私はDownloadStringAsync呼び出しを行っています。これらの呼び出しのうち3つが待機するため、私の主なアプリケーションでは、AutoResetEventを使用してそれらのすべてが終了するのを待機しています。だから私は彼らがコールバック関数で設定されるまでブロックします。C#スレッド化とAutoResetEventの使用

ただし、コールバックのテスト後に呼び出されることはありません。コードがAutoResetEventによってブロックされ、DownloadStringAsyncがブロックされていると思っています。このコードをコメントアウトすると、すべてうまく動作します。

だから私はすぐに呼び出すと思います:objNoGateway.NoGatewayStatus(sipUsername、statusDisplay1.PhoneNumber); コードがここに到達すると:handle.WaitOne(); クラスライブラリ内のコードをブロックします。何かアドバイスのため

感謝します。

私のクラスライブラリのコードサンプル。

 // Event handler that makes a call back in my main application 
    // Event handler and method that handles the event 
    public EventHandler<NoGatewayEventArgs> NoGatewayCompletedEvent; 
    // The method that raises the event. 
    private void OnNoGatewayCompleted(object sender, NoGatewayEventArgs e) 
    { 
     if (NoGatewayCompletedEvent != null) 
     { 
      NoGatewayCompletedEvent(this, e); 
     } 
    } 

    // Start the Async call to find if NoGateway is true or false 
    public void NoGatewayStatus(string sipUsername, string phoneNumber) 
    {  
     string strURL = string.Format("http://xxxxxxxxxxxxxxx={0}&CalledNumber={1}", sipUsername, phoneNumber); 

     if (!wc.IsBusy) 
     { 
      try 
      { 
       string errorMsg = string.Empty; 
       wc.DownloadStringAsync(new Uri(strURL)); 
      } 
      catch (WebException ex) 
      { 
       Console.WriteLine("IsNoGateway: " + ex.Message); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine("IsNoGateway: " + ex.Message); 
      } 
     } 
     else 
     { 
      Console.WriteLine("WebClient: IsNoGateWay(): Busy please try again"); 
     } 

    } 

    void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) 
    { 
     if (e.Error == null) 
     { 
      if (e.Result == "No gateway") 
      { 
       OnNoGatewayCompleted(this, new NoGatewayEventArgs(validateResponse_e.VALIDATION_FAILED)); 
       Console.WriteLine("NoGatway() DownloadedCompleted: " + e.Result); 
      } 
      else 
      { 
       OnNoGatewayCompleted(this, new NoGatewayEventArgs(validateResponse_e.OK)); 
       Console.WriteLine("NoGateway() DownloadCompleted: " + e.Result); 
      } 
     } 
     else 
     { 
      this.OnNoGatewayCompleted(this, new NoGatewayEventArgs(validateResponse_e.SERVER_FAILED)); 
      Console.WriteLine("No Gateway: DownloadCompleted() Error: " + e.Error.Message); 
     } 
    } 

私はこのコールバックを登録しています。そして結果を待つ。次に、AutoResetEventを設定します。

ManualResetEvent[] waitValidateCallResponse = new ManualResetEvent[] 
      { new ManualResetEvent(false), new ManualResetEvent(false), new ManualResetEvent(false) }; 
    // Event handler for NoGateway event 
    private void OnNoGatewayCompleted(object sender, NoGatewayEventArgs e) 
    { 
     Console.WriteLine("OnNoGatewayComleted: " + e.noGateway); 
     waitValidateCallResponse[0].Set(); 
    } 

私が呼び出してブロックするときの部分。

NoGateway objNoGateway = new NoGateway()   
objNoGateway.NoGatewayCompletedEvent += new EventHandler<NoGatewayEventArgs>(this.OnNoGatewayCompleted); 
objNoGateway.NoGatewayStatus(sipUsername, statusDisplay1.PhoneNumber); 


// Block here - Wait for all reponses to finish before moving on 
waitEvent.WaitOne(5000, true);      
Console.WriteLine("All thread finished");  

========================編集はただ一つだけを持つ私の問題を混同しないように、他の2つのコールバックを追加し、あなたは常にインデックス0に設定して呼び出します。======================

private void OnCalledNumberBlockedCompleted(object sender, CalledNumberBlockedEventArgs e) 
    { 
     Console.WriteLine("OnCalledNumberBlockedCompleted: " + e.CalledNumberBlocked); 
     waitValidateCallResponse[1].Set(); 
    } 

    private void OnValidTelephoneNumberCompleted(object sender, ValidTelephoneNumberEventArgs e) 
    { 
     Console.WriteLine("OnValidTelephoneNumberCompleted: " + e.validTelephoneNumber); 
     waitValidateCallResponse[2].Set(); 
    } 
+0

あなたのコードによれば、コンソールの "events.WaitOne():" + handle.ToString() を正確に一度読む必要があります。 あなたはあなたの記事でそれについて話しませんでしたが、それは貴重な手掛かりです。だから、それは起こったのだろうか? – DonkeyMaster

+0

この行には決して到達しません:Console.WriteLine( "events.WaitOne():" + handle.ToString()); – ant2009

+0

もし私がそれをデバッグしなければならなかったならば、私はデバッガで一歩踏み込んだでしょう。どのコード行が実行され、どの行が実行されないのかを教えてください。 コールバックは実行中ですか? wc_DownloadStringCompletedメソッドは実行されていますか? コードでは、OnValidTelephoneNumberCompletedメソッドとOnCalledNumberBlockedCompletedメソッドがどこで呼び出されたかを示していませんでした。 また、これは私を悩まします: public EventHandler NoGatewayCompletedEvent; 以上... NoGatewayCompletedEvent(this、e); これはコンパイルしないでください。あなたは "event"キーワードを書きませんでした。しかし、おそらく何もしていません。 – DonkeyMaster

答えて

1

は、として、それは同じくらい簡単ですか?

private void OnNoGatewayCompleted(object sender, NoGatewayEventArgs e) 
{ 
    Console.WriteLine("OnNoGatewayComleted: " + e.noGateway); 
    waitValidateCallResponse[0].Set(); 
} 
+0

実際に私は3種類のコールバックを持っています。シンプルにするために私はここにそのうちの1つだけを表示しました。他のコールバックは1と2を設定します。 ManualResetEventに変更しました。しかし、問題は残っている。私はこの行をコメントアウトする場合handle.WaitOne();私のコールバックが受信されます。しかし、コメントを外すと、UIがブロックされ、フリーズします。それ以上のご提案ありがとうございます。 – ant2009

+0

私はこのようなものが完了したイベントを呼び出すために使用されていると思う。 asyncOp.PostOperationCompleted(this.onCompletedDelegate、args); 非同期スレッドがPostOperationCompleteを使用して完了したデリゲートを呼び出すとき、呼び出し元クラスのスレッドコンテキストを使用します。非同期スレッドを開始した後に呼び出し元のスレッドコンテキストでWaitOneを呼び出した場合、呼び出し元クラスのスレッドがブロックされるため、非同期スレッドを実行できなくなります。 – Taliesin

0

多くの編集の後、私はこの問題を理解するかもしれないと思う。 Windowsフォームアプリケーションには1つのメインスレッドがあります。このスレッドはメッセージを処理するために使用されます。したがって、メインスレッドがブロックされている場合、アプリケーションはイベントを受け取ることができません。 WaitOneを使用してメインスレッドをブロックしたままにします。

WaitOne()チェックを別のタイマースレッドに移動します。

それとも、限られた時間を待って、との間でメッセージを処理するアプリケーションを指示することができます:

foreach (WaitHandle handle in waitValidateCallResponse) 
{ 
    while (!handle.WaitOne(300)) 
     Application.ProcessMessages(); 
    Console.WriteLine("events.WaitOne(): " + handle.ToString()); 
} 

後のアプローチはあなたががライブラリにやるべきものではありません。それは私が思うアンチパターンの何かです。次のように

+0

残りの2つのコールバックを追加しました。普通は、コードを長すぎて投稿できないので、私はそれらを見せなかった。 – ant2009

+0

この行には決して達しません。したがって、コンソールには書き込まないでください。 Console.WriteLine( "events.WaitOne():" + handle.ToString()); – ant2009

+0

OnNoGatewayCompletedには決して達しません。 waitOne()は、コールバックがコールバックする機会を得る前にすでにブロックしています。 – ant2009

0

スニペットコードは(.. OnNoGatewayCompletedがイベントを発生させるためのヘルパーメソッドのようです。..

// Event handler that makes a call back in my main application 
    // Event handler and method that handles the event 
    public EventHandler<NoGatewayEventArgs> NoGatewayCompletedEvent; 
    // The method that raises the event. 
    public void OnNoGatewayCompleted(object sender, NoGatewayEventArgs e) 
    { 
     if (NoGatewayCompletedEvent != null) 
     { 
      NoGatewayCompletedEvent(this, e); 
     } 
    } 

は、しかし第二の最後のスニペットでは、あなたがこのイベントのイベントハンドラをアタッチ特有のものであることパブリックにするべきではありません)が、ここではイベントハンドラに再度イベントを発生させているようです。あなたはOnNoGatewayCompleted(私はありません願っています)という名前の2つの方法

objNoGateway.NoGatewayCompletedEvent 
    += new EventHandler<NoGatewayEventArgs>(this.OnNoGatewayCompleted); 

を持っていない限り、あなたは、イベントハンドラに通知するwaitHandlesを探しているなら、この方法は、代わりにイベントにフックアップされOnCalledNumberBlockedCompletedべきではありません。

PS:マルクが指摘したように.. WaitHandle.WaitAllを使用する(forループの場合ではないかもしれないために、完全な非同期動作のことを要求する)

+0

ループが順番に完了するように要求していないと思いますか? – Andomar

+0

OnCalledNumberBlockedCompletedはフックされていますが、私はそれを表示しませんでした。私はちょうどNoGatewayイベントハンドラを使ってデモンストレーションしました。 – ant2009

-3

使用WaitHandle.WaitAny(handleArray)。 handle.WaitOne();の代わりにハンドル配列内のすべてのハンドルを待機します。ループ内で

+1

-1 WaitOneがブロックした場合、WaitAllはさらに難しくブロックされます – Andomar

+0

うん..あなたは正しいです...私は思っていたwhtを知りません!!! –

+0

それは難しくはありません...ループを除いて同じものになります –

1

は、これらの線に沿って何かを試してみてください:

public void NoGatewayStatus (string sipUsername, string phoneNumber) { 
    string strURL = string.Format("http://xxxxxxxxxxxxxxx={0}&CalledNumber={1}", sipUsername, phoneNumber); 

    ManualResetEvent wait1 = new ManualResetEvent(false); 
    WebClient wc = new WebClient(); 
    Thread thr = new Thread(DownloadSomeStuff); 
    thr.Start(new DlArguments(strURL, wait1)); 

    // do the other three 

    if (!wait1.WaitOne(10000)) { 
     Console.WriteLine("DownloadSomeStuff timed out"); 
     return; 
    } 
    if (!wait2.WaitOne(10000)) { 
     Console.WriteLine("DownloadOtherStuff timed out"); 
     return; 
    } 
    if (!wait3.WaitOne(10000)) { 
     Console.WriteLine("DownloadMoreStuff timed out"); 
     return; 
    } 
} 

public void DownloadSomeStuff (object p_args) { 
    DlArguments args = (DlArguments) p_args; 
    try { 
     WebClient wc = new WebClient(); 
     wc.DownloadString(args.Url); 
     args.WaitHandle.Set(); 
    } catch (Exception) { 
     // boring stuff 
    } 
} 


private class DlArguments 
{ 
    public DlArguments (string url, ManualResetEvent wait_handle) { 
     this.Url = url; 
     this.WaitHandle = wait_handle; 
    } 

    public string Url { get; set; } 
    public ManualResetEvent WaitHandle { get; set; } 
} 

が、これはそれを行うのですか?

+0

私はあなたが何を意味しているかを理解していると思います。私はあなたに知らせようとします。 – ant2009

関連する問題