2012-11-04 2 views
0

조금 문제가 생겼습니다. 매번 GUI의 스레드로 숫자를 보내거나 반환해야하는 루프를 실행하는 두 개의 스레드가 있습니다. 이를 위해 BackGroundWorkerReportProgress을 사용합니다. 내가 실행하는 BackgroundWorker에 (DoWork) 어떤 0에서 계산하는 간단한 루프를gui 동결없는 간단한 작업

:

하자가 그런 말을. 루프에 대한 모든 항목은 카운터 값을 인쇄 할 GUI 스레드에 ReportProgress 이벤트를 사용하여 카운터를 보냅니다.

void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     int count = 0; 
     BackgroundWorker Worker = (BackgroundWorker)sender; 

     while (count < 10000000) 
     { 
      Worker.ReportProgress(count); 
      count++; 
     } 
    } 

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     txt.Text = e.ProgressPercentage.ToString(); 
    } 

이제는이 기능이 GUI를 고정시킵니다.

ReportProgress가 BackGroundWorker을 만든 스레드에서 ProgressChange 처리기를 호출한다는 것을 알고 있습니다. 그래서 루프가 너무 빨리 실행되어 GUI의 스레드가 필요에 따라 값을 인쇄하지 못하고 있다고 생각합니다.

무엇 GUI를 멈추지 않고 그런 작업을 수행 할 수 있습니까?

Dispatcher에 대해 들었지만 그 내용이 무엇인지 잘 모르겠습니다.

+2

GUI가 맞습니까? GUID는 내가 아는 한 완전히 다른 무언가이기 때문에 :-) 또한 WinForms를 사용하고 있습니까? 아니면 WPF를 가정 할 수 있습니까? – Daneo

+0

'GUI' = 그래픽 사용자 인터페이스; GUID = Globally Unique IDentifier ... 그냥 FYI;) –

답변

3

문제점은 무언가가 변경 될 때마다 reportProgress를 호출하는 것이 문제입니다. 진행 상황을보고해야하는 경우에만 호출해야합니다. MSDN http://msdn.microsoft.com/en-us/library/ka89zff4.aspx을 참조하십시오. 이런 식으로 dowork 변경 :

while (count < 10000000) 
    { 
     if ((count % 1000) == 0) 
      Worker.ReportProgress(count); 
     count++; 
    } 

이 각각 1,000 처리 항목 후 ReportProgress 전화 때문에 당신의 GUI 스레드에 불필요한 부하를 넣어하지 않습니다

+0

예. 알고 있습니다.하지만 이건 원래 루프가 아닙니다. 원래의 루프는 그보다 훨씬 큰 값을 사용합니다. GUID의 스레드. – Matan

0

나는 같은 작업을 수행 할 수있는 GUID를 동결하지 않고? :

디스패처를 사용하여이 날 ​​당신은 어쨌든, WPF를 사용하는 가정했다, 그것은 것 다음 Dispatcher.BeginInvoke를 호출

void worker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    int count = 0; 
    BackgroundWorker Worker = (BackgroundWorker)sender; 

    while (count < 10000000) 
    { 
     Worker.ReportProgress(count); 
     count++; 
    } 
} 

void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
{ 
    Dispatcher.BeginInvoke((Action)(() => { txt.Text = e.ProgressPercentage.ToString(); })); 
} 

가 실제로 UI 스레드에서 실행되도록 주어진 행동을 유발하기 UI 요소에 액세스하는 UI 스레드 이외의 스레드의 원인으로 예외가 발생하지 않습니다.

또한, 그래서 GUI 윈도우 메시지를 홍수, 업데이트 알림 메시지를 처리 ​​할 수있는 GUI보다 훨씬 빠른 속도로 GUI를 업데이트하려고 단지 대안 by using a task.

+1

ProgressChanged 이벤트 처리기는 백그라운드 작업자를 만든 스레드에서 호출됩니다. 그러나 UI 스레드에서 생성되지 않은 경우에도 UI를 차단하지 않고 예외가 발생합니다. – Ondra

+0

그건 작동하지 않았지만, 왜 당신이 그렇게하기로 결정했는지 정말로 이해하지 못했습니까? – Matan

+0

@Matan 스레드 안전성에 대해 생각하고 있는데, dispatcher를 호출하면 UI 스레드에서 작업이 100 % 수행됩니다. 루프에 Thread.Sleep (500)을 넣으면 그에 따라 업데이트되는 UI가 표시됩니까? – Daneo

1

당신의 예제 코드로,이 시도 할 수 있습니다 gunge로 큐에 넣고 다른 메시지를 처리하는 것을 막는다.

폴링이 더 나은 솔루션 일 때 비 GUI 스레드에서 고속 작업의 진행 상황을 모니터링하는 것이 몇 번만 있습니다. Forms.Timer 이벤트를 사용하여 스레드의 메서드에서 반환 한 'currentProgress'값을 읽고 표시합니다. 500ms는 합리적인 타이머 값입니다. 인간 사용자는 편집/텍스트 상자에서 변경되는 정수 값을 훨씬 빠른 속도로 따라갈 수 없습니다.

'이상적'으로, currentProgress 값의 읽기/쓰기는 아마도 원자 연산으로 잠겨 야합니다.하지만 500ms마다 int 값을 읽는다면 아마도 ' 스레드의 실제 기능은 진행 카운트가 레지스터에 연속적으로 캐시 될 가능성이 거의 없음을 의미합니다.

+0

고마워요, 이것 역시 제가 생각한 것입니다. 그래서 마지막으로, backgroundWorker를 만든 스레드가 진행률 카운터를 읽을 수 있습니까? – Matan

+0

내 말은 backgroundworker를 만든 스레드가 backgroundworker 스레드에 속한 currentProgress 값에 액세스 할 수 있습니까? – Matan

관련 문제