2009-05-11 3 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를 설정하십시오.

내가 전화를 걸고 차단할 때의 부분.

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, 인수); 비동기 스레드가 호출 클래스의 스레드 컨텍스트를 사용 완료 대리자를 호출 할 PostOperationComplete를 사용 . 비동기 스레드를 시작한 후 호출 한 스레드 컨텍스트에서 WaitOne을 호출 한 경우 호출 클래스 스레드가 차단되면 호출 스레드 컨텍스트를 실행할 수 없습니다. – Taliesin

0

많은 수정 작업을 마친 후에 문제를 이해할 수 있습니다. Windows Forms 응용 프로그램에는 하나의 주 스레드가 있습니다. 이 스레드는 메시지를 처리하는 데 사용됩니다. 따라서 주 스레드가 차단되면 응용 프로그램에서 이벤트를 수신 할 수 없습니다. 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); 
     } 
    } 

그러나 2 마지막 코드에서,이 이벤트에 대한 이벤트 처리기를 부착 특유의 그 공개해서는 안됩니다.)하지만 여기에서는 이벤트 핸들러에서 이벤트를 다시 발생시킨 것으로 보입니다.당신이 OnNoGatewayCompleted라는 이름의 2 가지 방법이 없다면 당신은 waitHandles이 이벤트 처리기에서 신호를 받도록를 찾고 있다면

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

(I하지 바라고 있어요), 방법 대신 이벤트에 매여 수 OnCalledNumberBlockedCompleted 안 .

추신 : 마크는 지적 .. WaitHandle.WaitAll를 사용 (for 루프는 경우하지 않을 수 있도록하는 비동기 작업이 완료 요구)

+0

루프가 순서대로 완료해야한다고 생각하지 않습니까? – Andomar

+0

OnCalledNumberBlockedCompleted은 더 이상 게시물을로 만 나는 그것을 보여주지 않았다, 후크입니다. 방금 NoGateway 이벤트 처리기로 시연했습니다. – ant2009

-3

사용 WaitHandle.WaitAny (handleArray); 핸들 배열에서 handle.WaitOne() 대신에 모든 핸들을 기다려야합니다. 루프

+1

-1 WaitOne 블록, WaitAll가 훨씬 더 힘들어 차단합니다 경우 – Andomar

+0

아, 그래 ... 당신 말이 맞아 ... 내가 생각을했다 WHT 잘 모릅니다! –

+0

은 늘 ... w를 제외하고는 동일합니다 더 열심히하지만 수/루프 –

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