2011-07-05 2 views
1

윈도우 폼에서 버튼을 클릭 할 때 두 개의 다른 스레드에서 실행해야하는 두 개의 독립적 인 함수가 있습니다.여러 독립 스레드가 실행 된 경우 UI에서 레이블 텍스트를 업데이트하는 방법 Join의 사용법은 무엇입니까

두 스레드가 완전히 실행되면 Form의 상태가 "Status Updated"로 설정되어야합니다.

어떻게하면됩니까?

EDIT 다음 코드를 실행하려고하는데 문제를 파악할 수 없습니다. 내가 Join을 호출하면. 내 스레드가 무한대로 고정됩니다.

Thread t1, t2; 

    int cT1; 
    int ctT2; 

    private void btnStart_Click(object sender, EventArgs e) 
    { 
     t1 = new Thread(CountN); 
     t2 = new Thread(CountT2); 
     t1.Start(int.Parse(txtT1.Text)); //3 
     t2.Start(int.Parse(txtT2.Text)); //4 
     t2.Join(); 
     label1.Text = (cT1 + ctT2).ToString(); 
    } 

    private void CountN(object sender) 
    { 
     for (int i = 0; i < (int)sender; i++) 
     { 
      cT1++; 
      if (lblMsg.InvokeRequired) 
       lblMsg.Invoke(new Action<int>((x) => lblMsg.Text = x.ToString()), cT1); 
     } 
    } 

    private void CountT2(object sender) 
    { 
     for (int i = 0; i < (int)sender; i++) 
     { 
      ctT2++; 
      if (lblMsg2.InvokeRequired) 
       lblMsg2.Invoke(new Action<int>((x) => lblMsg2.Text = x.ToString()), ctT2); 
     } 
    } 

답변

1

UI 스레드에서 Thread.Join을 호출했기 때문에 UI 스레드와 작업자 스레드가 교착 상태가됩니다. Join은 대상 스레드가 완료 될 때까지 호출 스레드를 차단합니다. 블록이 UI 스레드에서 발생하기 때문에 메시지 펌프가 Windows 메시지를 디스패치하고 처리하지 못합니다. 그러나 UI 스레드가 차단 된 경우이 메커니즘이 발생하지 않습니다. 작업자 스레드는 Control.Invoke을 호출하여 해당 스레드의 메시지 큐에 메시지를 보내서 대리인의 실행을 마샬링하고 해당 대리인의 실행이 완료 될 때까지 대기합니다. 그러나 UI 스레드가 Join에 대한 호출을 차단하는 것과 같이 무언가를하고있을 때 바쁘면 해당 대리자가 절대 완료되지 않고 Invoke이 무기한 차단됩니다. 이 상황은 JoinInvoke이 서로 교착되어 교착 상태가되는 시나리오로 연결됩니다.

여기 실제 문제는 UI 스레드에서 Join을 호출하는 것입니다. 교착 상태가 발생할 수 있고 단추 클릭이나 양식 렌더링과 같은 Windows 메시지 처리를 막을 수 있으므로 UI ​​스레드로부터 차단 메서드를 호출하면 안됩니다. 사용자 인터페이스는 최종 사용자의 관점에서 완전히 매달려 있습니다.

이 문제가 Join에 전화를 제거 수정하고 바로 작업자 스레드가 완료가 있음을 나타냅니다 로직을 실행하는 작업자 스레드에서 for 루프 후 Control.Invoke에 다른 통화를 추가합니다. 귀하의 경우 로직은 label1을 최종 결과로 업데이트하는 것입니다.

+0

't2.Join();을 사용하여 Join은 호출 스레드를 차단하지만이 행은 의미합니까? 이 라인이 쓰여진 쓰레드는 t2 쓰레드가 완료되지 않으면 차단 될 것입니다. 또한 "Delegate의 실행을 UI에 마샬링 할 Control.Invoke"를 설명하십시오. –

+0

예,'Join'은't2'가 끝날 때까지 호출 스레드를 차단합니다. '통제.Invoke'는 작업자 스레드에서 대리자를 실행하지 않습니다. 대신'Control' 레퍼런스 (UI 스레드)를 호스팅하는 스레드에서이를 실행합니다. 이 작업을 수행하기 위해 UI 스레드의 메시지 큐에 메시지를 게시하는 마샬링 작업을 사용합니다. –

0

Control.Invoke를 사용하여 주 스레드에서 메서드를 호출 할 수 있습니다. 대리인은 컨트롤과 안전하게 상호 작용할 수 있습니다. 자세한 내용은 this을 참조하십시오.

0

Thread.Join()을 사용하면 스레드가 완료 될 때까지 대기하고 현재 스레드를 차단할 수 있습니다.

1

예쁜 기본적인 방법 :

Pseudocode 
    bool thread1Complete = false 
    bool thread2Complete = false 
    StartThread1() 
    StartThread2() 

    Thread1CompletedEventHandler(): 
     thread1Complete = true 
     UpdateUI() 

    Thread2CompletedEventHandler(): 
     thread2Complete = true 
     UpdateUI() 

    UpdateUI(): 
     if thread1Complete and thread2Complete then 
      SetStatusText() 

세부 사항이 스레딩 구현에 따라 달라집니다. BackgroundWorker를 사용하는 경우 Control.Invoke()를 사용하여 상태 컨트롤을 업데이트 할 필요는 없지만 스레드에서 ThreadXCompletedEventHandler() 메서드를 호출하면 Control.Invoke()를 사용해야합니다.

.NET 4를 타겟팅하는 경우 작업을 살펴볼 수 있습니다.

관련 문제