代码之家  ›  专栏  ›  技术社区  ›  He Shiming

计时器排队,是否立即终止计时器?

  •  2
  • He Shiming  · 技术社区  · 16 年前

    我正在尝试通过使用Windows计时器队列在Windows GDI上实现每秒高帧。相关的API是 CreateTimerQueue, DeleteTimerQueueEx, CreateTimerQueueTimer, DeleteTimerQueueTimer .

    计时器是使用 CreateTimerQueueTimer(&m_timer, m_timer_queue, TimerCallback, this, 0, 20, WT_EXECUTEINTIMERTHREAD); 以达到大约50fps的速度。gdi操作(一些在后台绘制,加上invalidrect)不能是异步的,因此我不能选择其他标志,但wt_executeintimerThread,这样绘图代码就不需要额外的同步操作。我们的想法是在可能的时候达到50帧,如果不可能的话,只需以最大可能的速度显示每一帧。

    动画结束时(达到总帧数) 删除时间队列计时器 调用以销毁计时器。

    问题是 删除时间队列计时器 不会立即关闭回调函数的调用。当不能达到50fps的要求时,计时器将呼叫泵入队列。打电话 删除时间队列计时器 回调函数内部不会破坏队列。因此,即使决定关闭计时器,回调仍在被调用。

    我该如何处理这个问题?

    - 在另一张纸条上,旧的 timeSetEvent / timeKillEvent 多媒体API似乎没有这个问题。没有队列,当我调用TimeKillEvent时,回调函数的调用将立即停止。是否可以实现与计时器队列相同的行为?

    3 回复  |  直到 14 年前
        1
  •  2
  •   Dunk    16 年前

    您可以将wt_ExecuteOnlyOnce标志传递给createTimerQueueTimer函数。这将导致计时器只触发一次,而不是周期性地触发。

    然后可以使用ChangeTimerQueueTimer方法重新安排计时器。

    要覆盖在帧中绘制的时间太长、太完整,可以在TimerHandler方法的开头添加一个CriticalSection,这将导致第二个计时器等待第一个计时器完成。

        2
  •  1
  •   Ana Betts    16 年前

    如果你想以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;
    }
    
        3
  •  1
  •   quixver    14 年前

    如果计时器尚未计划,则DeleteTimerQueueTimer将取消该计时器。(当您使用wt_ExecuteTimerThread时,我相信它们作为线程上的APC从计时器队列和工作线程共享的线程池排队。)如果它已经被调度(而不仅仅是运行),它将被运行,并且DeleteTimerQueueTimer调用将被阻塞,直到完成为止。

    如果我正确理解你的问题,我可以提出以下建议吗? 1。在调用DeleteTimerQueueTimer之前-将标志say abortalTimers设置为true。 2。在每个计时器回调函数中,检查abortalTimers是否为true。如果是真的-那么立刻返回,不做任何绘制。

    最后,不应从计时器回调调用-deleteTimerQueueTimer。相反,我建议您应该从任何其他线程调用它——比如您用来启动计时器的线程。

    希望这有帮助。