8.23 MFC定时器

        定时器不是通过开启单独的线程执行的,而是操作系统的消息获取分发机制,不断的在时间值到达之后去执行定时器中的任务。其实是主线程一直在定时触发定时器,调用定时器。也许这样表达不对,但是这样却让我理解。

如果定时器阻塞,则是主程序被阻塞掉,主程序则无法再继续运行下去。即:定时器不是多线程。参阅别人的一篇文章加深理解:

首先说明,这个结果绝对不是多线程引起的。有同学开始认为是多线程,每次OnTimer调用单独开一个线程。但我打开任务管理器跟踪发现线程并没有增加。于是我上csdn请教高手,经过一个下午的讨论,才算弄明白,其核心问题还在于消息机制。

     如果用Windows API写过程序,你应该明白在WinMain中有一个消息循环,不断的取消息,转换,重新发送消息,代码如下:

// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
   if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
   {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
   }
}

     通过GetMessage得到一个消息,如果没有消息,则会阻塞到这里。这个消息从哪里来?操作系统。操作系统为每个线程创建一个消息队列(在收到第一个消息时真正创建),而每个线程可以包括多个窗口。也就是说,这个消息队列包括了该线程中所有的窗口消息。因此,通过GetMessage获取消息时,当第二个参数为NULL时,会将同线程中其他窗口的消息也得到。然后进行消息转换,首先转换快捷键为相应的消息,然后转换你的键盘操作,通过消息转换将其解析为到底是输入字符,还是控制键。转换完成后,再通过DispatchMessage来分发消息。分发给谁?操作系统。操作系统收到消息后,调用消息所属窗口的WndProc函数,根据消息的类型进行处理。处理完成后,操作系统将控制权再转交给程序,完成Dispatch,继续进行消息循环。

     这里需要注意的就是,每个窗口的消息循环不只是处理本窗口的消息,也将同线程下其他窗口的消息也处理掉了。这就是为什么当OnTimer弹出一个对话框后还可以继续弹出对话框,是因为弹出的MessageBox本身的消息循环接替了上一个窗口循环的工作。如此递归调用,这也是为什么消息机制支持嵌套调用。这里有一个问题,DispatchMessage为什么不由程序本身来调用,而非要经过操作系统?这就是出于便捷考虑,如果直接处理,那么一个窗口必须有权限访问其他窗口的处理函数,不然怎么实现处理其他窗口的调用呢?这就是回调函数的优点。

     另外一个问题,程序在执行消息时,会不会在一条消息处理没有完毕时,就去处理下一条?比如不断的调用OnTimer?答案是不会,除非在处理函数中有一个消息循环,类似于本文的案例。否则,只可能在一条消息处理完毕后,才执行下一条。

     OnTimer的定时是不精确的,并且WM_TIMER消息的优先级非常低,总是添加到消息队列的尾部。并且同一个定时器消息只会在队列中出现一次,类似于WM_PAINT消息。你不用担心在OnTimer处理函数中执行太久后收到一堆的WM_TIMER消息,但你也要注意,你的WM_TIMER消息已经丢失了一些。


你可能感兴趣的:(mfc,多线程,timer,任务,null,windows)