2009-10-27 2 views
1

나는 100ms마다 무언가를 그려야하는 Form에 PictureBox 컨트롤이 있습니다.Invoke를 사용하여 백그라운드 스레드 작업에 절전 모드로 전환하는 방법

백그라운드 스레드는 루프에서 계산을 수행하고 모든 반복 후에 이벤트를 발생시킵니다.

편집(코멘트에 대한 응답으로) :

world.OnPieceStep += DrawScreen; 
: 기본 폼 내부

World world = new World(); 

void CreateBackgroundThread() { 
    Thread backgroundThread = new Thread(world.BackgroundWorkerFunction); 
    backgroundThread.Start(); 
} 

 

public class World { 

    void BackgroundWorkerFunction() { 
     IPiece piece = PieceFactory.Create(); 
     for (int i = 0; i < stepsCount; i++) { 
      piece.Calculate(); 
      if (OnPieceStep != null) { 
       OnPieceStep(piece); 
      } 
     } 
    } 

} 

가 설정 한 핸들러가

a Invoke 래퍼 (draw 할 컨트롤이 UI 스레드에서 생성되기 때문에).

이제
void DrawScreen(IPiece piece) { 
    this.Invoke(new PieceStep(_drawScreen), piece); 
} 
void _drawScreen(IPiece piece) { 
    drawer.Draw(world.Board, piece); 
} 

, 나는 각 반복 후 100ms의 작업을 일시 중지하도록 루프에 대한 싶습니다, 그래서 (100)에 Thread.sleep 추가; 이벤트를 발사하기 전에 :

for (int i = 0; i < stepsCount; i++) { 
    IPiece piece = Calculate(); 
    if (OnPieceStep != null) { 
     Thread.Sleep(100); 
     OnPieceStep(piece); 
    } 
} 

이 그러나 PictureBox를마다 100 밀리 새로 고침하지만 루프의 마지막 반복을 그립니다 만 루프 완료 후하지 않습니다.

UI 스레드가 아니라 스레드가 스레드를 일시 중지하지 않아야합니까?   업데이트 : 백그라운드 스레드가 계산되는 동안 앱을 클릭하려고했습니다. 프로그램이 ("응답하지 않음") 차단하므로 Thread.Sleep이 UI 스레드에서 분명히 호출되었습니다. 예상되는 동작입니까, 아니면 스레딩에 문제가 있습니까?

+0

루프 위치는 어디입니까? –

+0

호출 구조를 반영하도록 코드를 편집했습니다. –

+0

그림을 만든 후에 그림 상자를 무효화하고 있습니까? – Simon

답변

1

:

Thread.sleep를가한다는 점에서 차단 방법 사이에 고유 한 것은 Windows 메시지가 윈도우 내에서 펌핑이 유보 스레드에 환경을 Forms 응용 프로그램 또는 COM되는 을위한 단일 스레드 아파트 모델은 입니다. "에 관계없이 입니다 펌핑 여부 메시지의 - 따라서 일반적으로 피해야 입니다 - 윈도우 에 어떤 긴 차단 작업이 메인 UI 스레드가 응용 프로그램이 응답하지 만들 것 에, Forms 응용 프로그램과 함께이 작은 결과 이다 기술적으로 "중단되었습니다. 상황은 COM 호스트 환경에서 더 복잡합니다. 메시지 전달을 유지하는 동안 이 잠자기하는 것이 바람직한 경우가 있습니다. Microsoft의 Chris Brumme은 웹 로그 (search : 'COM "Chris Brumme")에서 길이가 임을 설명합니다.

WinForms의 Thread.Sleep()은 스레드가 호출 되더라도 UI를 항상 일시 중지하는 것으로 보입니다.

1

스레딩 장래성으로부터 모든 것이 잘 보입니다. 대부분의 문제는 _drawScreen (IPiece 조각) 방법에 의존합니다. 그리기 후에 창 새로 고침/업데이트를 시도 했습니까?

통찰력 : Control.Invoke 메서드는 Win32 SendMessage 함수를 사용하여 창 메시지로 매개 변수로 제공된 대리자를 전달합니다.

this page에 언급 한 바와 같이
+0

Thread.Sleep을 호출해서는 안되는 스레드를 멈추지 않아야합니까? (for 루프는 UI 스레드에서 작동하지 않습니다.) 시간 초과 이벤트가 아니기 때문에 타이머를 사용할 수 없지만 계산에 의존합니다. 필자가 원하는 것은 계산이 끝난 후 작업자 스레드가 100ms를 일시 중지 한 다음 이벤트를 발생시키는 것입니다. 계산 기간도 1 분일 수 있으므로 100ms마다 발생하는 타이머는 사용할 수 없습니다. 타이머를 사용할 수있는 유일한 방법은 이벤트를 100ms 동안 연기하는 것이지만 코드가 더 깨끗한 방법이라고 생각했습니다. –

+0

_drawScreen()은 빈 비트 맵을 만들고 Graphics.FromImage를 가져 와서 일부 원을 그린 다음 pictureBox.Image를 비트 맵으로 설정합니다. 이것은 UI 스레드 (Invoke 때문에)에서 모두 수행되므로 각 반복 후에 그려서는 안되는 이유를 알 수 없지만 전체 루프가 완료된 후에 만 ​​표시됩니다. –

관련 문제