2009-11-05 4 views
1

Windows Tier Queues를 사용하여 Windows GDI에서 초당 프레임 수를 높이려고합니다. 관련 API는 CreateTimerQueue, DeleteTimerQueueEx, CreateTimerQueueTimer,DeleteTimerQueueTimer입니다.타이머 대기열은 즉시 타이머를 종료합니까?

타이머는 약 50fps의 속도를 달성하기 위해 CreateTimerQueueTimer(&m_timer, m_timer_queue, TimerCallback, this, 0, 20, WT_EXECUTEINTIMERTHREAD);을 사용하여 생성됩니다. GDI 작업 (백 스토어의 일부 그림과 InvalidateRect)은 비동기 적이 지 않으므로 다른 플래그를 선택할 수는 없지만 WT_EXECUTEINTIMERTHREAD를 사용하여 그리기 코드에 추가 동기화 연산이 필요하지 않습니다. 가능한 경우 50fps를 달성하는 것이 아이디어이며, 그렇지 않은 경우 각 프레임을 가능한 최대 속도로 표시하십시오.

애니메이션이 끝날 때 (총 프레임 수에 도달) DeleteTimerQueueTimer이 호출되어 타이머가 삭제됩니다.

DeleteTimerQueueTimer은 즉시 콜백 기능의 호출을 끄지 않습니다. 50fps 요구 사항을 달성 할 수없는 경우 타이머는 호출을 대기열로 보내줍니다. 콜백 함수 내에 DeleteTimerQueueTimer을 호출해도 대기열이 삭제되지 않습니다. 결과적으로 콜백은 타이머를 종료하기로 결정 했음에도 여전히 호출 중입니다.

이 문제는 어떻게 해결합니까?

- 또 하나의 오래된 timeSetEvent/timeKillEvent 멀티미디어 API에는이 문제가없는 것 같습니다. 대기열이 없으며 timeKillEvent를 호출하면 콜백 함수 호출이 즉시 중지됩니다. 타이머 대기열에서 동일한 동작을 수행 할 수 있습니까?

답변

2

당신은 CreateTimerQueueTimer 함수에 WT_EXECUTEONLYONCE 플래그를 전달할 수 있습니다. 이렇게하면 타이머가 한 번만 트리거되고 주기적으로 트리거되지 않습니다.

그런 다음 ChangeTimerQueueTimer 메서드를 사용하여 타이머를 다시 예약 할 수 있습니다.

프레임에서 너무 많은 시간이 소요되는 시간을 처리하려면 TimerHandler 메서드 시작 부분에 CriticalSection을 추가하면 첫 번째 타이머가 완료 될 때까지 두 번째 타이머가 대기하게됩니다.

1

무언가를 50fps 이상으로 실행하려면 실제로 프레임 사이의 시간을 계산하고 이에 따라 애니메이션의 크기를 조절하는 드로우 루프가 있어야합니다. 타이머는 실제로 그렇게 자주 발생시키는 것은 아닙니다. 그래서 (그리고 아마 당신의 유휴 핸들러에있을 것입니다). 마찬가지로,이 의사 코드 (오류 처리의 부족을 무시) :

static longlong last_frame; 
while(1) { 
    longlong current_frame = QueryPerformanceCounter(); 
    long delta = current_frame - last_frame; 

    // Do drawing here, scale amount to move by how much time has elapsed 

    last_frame = current_frame; 
} 
+0

고마워,하지만 어떻게 멀티미디어 타이머 API 가이 문제가 없어? 어떤 종류의 간격이 "너무 자주"아닌가? "while (1)"과 "QueryPerformanceCounter"가 멀티미디어 타이머 또는 타이머 대기열 타이머보다 훨씬 비싸지 않습니까? 지금까지 나는 타이머 큐 타이머가 거의 50fps의 콜백을 발생시키는 데 드는 비용이 들지 않으면 서, 멀티미디어 타이머는 단지 약간의 CPU 비용만을 요구한다는 것을 발견했다. –

0

DeleteTimerQueueTimer는 아직 예약되지 않은 타이머를 취소합니다. (WT_EXECUTEINTIMERTHREAD를 사용하면 타이머 큐와 작업자 스레드가 공유하는 스레드 풀의 스레드에서 APC로 대기하고 있다고 생각됩니다.) 이미 실행 된 것이 아니라 일정이 잡혀 있으면 실행되고 DeleteTimerQueueTimer 호출 완료 될 때까지 차단됩니다.

문제를 올바르게 이해하면 다음을 제안 할 수 있습니까? 1. DeleteTimerQueueTimer를 호출하기 전에 - abortAllTimers 플래그를 true로 설정하십시오. 2. 각 타이머 콜백 함수에서 abortAllTimers가 true인지 확인합니다. 그것이 사실이라면 - 그리기를하지 않고 한 번에 돌아 오십시오.

마침내 - DeleteTimerQueueTimer는 타이머 콜백에서 호출하면 안됩니다. 대신 다른 스레드에서 호출해야한다고 제안합니다. 타이머를 시작하는 데 사용한 스레드를 말하십시오.

희망이 도움이됩니다.

+0

타이머 콜백 함수에서 DeleteTimerQueueTimer를 호출하면 세 번째 매개 변수에 NULL을 전달하여 비 차단이되는 것이므로 완벽하게 좋습니다. [링크] (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682569(v=vs.85).aspx)를 참조하십시오. – Derek

+0

@Derek NULL을 전달하면 괜찮습니다. 3 번째의 파라미터 그러나 타이머가 완료되면 타이머 콜백에 사용 된 리소스를 정리하는 것이 안전 할 때 알 수 없습니다. –