2012-03-22 2 views
2

내 응용 프로그램은 매우 큰 데이터의 복잡한 처리를 수행하기 위해 스레드에 크게 의존합니다. 처리가 완료되면 UI를 업데이트해야합니다. UI를 업데이트하는 방법을 알고 BackgroundWorker'sOnProgressChangedRunWorkerCompleted 메서드를 사용하려고했습니다. 또한 업데이트 할 UI 스레드의 Invoke 메서드를 사용합니다. Win XP 32 비트 및 64 비트 OS에서는 모두 잘 작동하는 것으로 보입니다. Win Vista 및 Win 7 (32 및 64 비트)에서는 Invoke 메서드를 사용하여 UI를 업데이트하는 동안 응용 프로그램이 임의로 멈 춥니 다.C에서 스레드에서 UI를 업데이트하는 다른 방법

Invoke의 동작이 다른 Windows OS에서 변경됩니까? Invoke을 제외한 스레드에서 UI를 업데이트하는 다른 방법은 무엇입니까?

감사

+0

다른 OS와 환경에서는 UI를 업데이트하는 데 시간이 오래 걸립니다. – RQDQ

+1

문제는 새로운 OS라고 생각하지 않습니다. 제 생각에 새 컴퓨터가 더 빠르거나 더 많은 코어 (동시성 문제가 일찍 도착할 수도 있습니다)가 있거나 운이 좋다면 어쨌든 : 코드가 없으면 " 우리가 당신을 도울 수 있다고 생각하지 마십시오 – Carsten

+1

응용 프로그램이 응답하지 않거나 자체를 새로 고치지 않습니까? –

답변

2

Invoke 동작이 다른 Windows OS에서 변경됩니까?

아니요, 아니요. 그러나 스레딩 문제는 예측할 수없는 방식으로 실현 될 수 있습니다. 알 수없는 문제가있을 수 있습니다.

Invoke와 별도로 스레드에서 UI를 업데이트하는 다른 방법은 무엇입니까?

Invoke 또는 BeginInvoke을 사용하면 간단한 진행 정보를 UI 스레드에보고 할 때 특히 유용합니다. 주제와 관련된 일부 대답을 검색하면 항상이 접근 방법을 사용하는 것을 볼 수 있습니다. 그리고 좋은 이유는이 기술을 사용하는 데 많은 단점이 있기 때문입니다. BackgroundWorker이이 메커니즘을 ProgressChanged 이벤트를 통해 UI를 업데이트하는 용도로만 사용한다는 것은 불행한 일입니다.

다른 방법 중 하나는 작업자 스레드가 진행 변수 정보를 공유 변수에 게시하고 UI 스레드가 타이머를 통해 주기적으로 폴링되도록하는 것입니다. 마샬링 기술에 대해이 접근법을 정당화하는 데있어 필자가 평소에 말했던 몇 가지 점에 대해 설명합니다.

  • InvokeBeginInvoke은 값 비싼 연산입니다.
  • UI 스레드는 폼과 컨트롤을 업데이트하는시기와 빈도를 지정합니다.
  • ISynchronizeInvoke이 부과하는 UI와 작업자 스레드 간의 밀 결합을 제거합니다.
  • 마샬링 작업이 많아 지거나 UI 메시지 큐가 과도하거나 채워질 위험이 없습니다.
  • Invoke의 경우와 같이 응답을 기다릴 필요가 없기 때문에 작업자 스레드에서 더 많은 처리량을 얻을 수 있습니다.
+0

이 방법을 보증 할 수 있습니다. 나는 초당 100 회의 업데이트를받는 애플리케이션을 작성했다. (over middleware) 위와 같은 방법을 사용하기 위해 각 사람과 모든 사람을 표시하는 것은 어리 석다. 결과는 훨씬 유용하게 사용할 수 있습니다. – Fen

1

당신은 매개 변수로 Dispatcher.Priority 열거 걸리는 호출() 또는 BeginInvoke() 오버로드 중 하나를 사용하여 시도 할 수 있습니다. '배경'과 같은 매개 변수를 선택하면 응용 프로그램이 여전히 응답하는 것을 볼 수 있습니다. 유일한 문제는 계속 증가하는 대기열없이 적절한 속도로 수신 데이터를 서비스하고 있는지 확인하는 것입니다.

2

잘 모르겠지만, 항상 System.Windows.Forms.Timer을 실행하면 GUI가 주기적으로 업데이트됩니다. 필요한 경우 잠금 내에서 스레드간에 원시 데이터를 전달하기 위해 일부 멤버 변수를 사용하십시오. 가장 세련된 솔루션은 아니지만 스레드가 더 독립적이기 때문에 스레드가 Invoke의 기본 스레드에 의존하지 않고 매달려있는 것에 대해 다른 관점을 제공 할 수 있습니다.

+1

+1 : 반대로 진행 정보를 폴링하는 것은 종종 더 우아합니다. –

0

또 다른 옵션은 멀티 스레딩을 완전히 피하는 것입니다. 장기 실행 작업을 청크로 분해 할 수있는 경우 GUI 스레드에서 수행하고 Application.DoEvents()을 사용하여 GUI를 업데이트하십시오.

GUI를 업데이트 할 수있을뿐만 아니라 사용자 입력에 대한 응답을 시작하고 타이머 등을 시작할 수 있기 때문에 나는이 메소드의 사용을 싫어 했었지만 궁극적으로 백그라운드 스레드를 사용하는 것보다 덜 안전합니다. GUI를 사용하여 언제든지 작업을 시작할 수 있습니다. 따라서 Application.DoEvents()이 호출 될 때마다 _canceled 또는 기타 사항을 확인해야합니다. (결국이 메소드의 존재를 싫어하기로 결정했다. 선형 실행 순서의 보장을 제거하기 때문이다.).

물론이 방법으로 멀티 코어 지원을 잃어 버리므로 동시에 많은 백그라운드 작업을 실행하려는 경우 성능에 영향을 미칩니다.

관련 문제