Win32消息循环机制等【转载】http://blog.csdn.net/u013777351/article/details/49522219 (7)

  当该程序没有消息通知时getMessage就不会返回,也就不会占用系统的CPU时间。 
  在16位的系统中系统中只有一个消息队列,所以系统必须等待当前任务处理消息后才可以发送下一消息到相应程序,如果一个程序陷如死循环或是耗时操作时系统就会得不到控制权。这种多任务系统也就称为协同式的多任务系统。Windows3.X就是这种系统。 
  而32位的系统中每一运行的程序都会有一个消息队列,所以系统可以在多个消息队列中转换而不必等待当前程序完成消息处理就可以得到控制权。这种多任务系统就称为抢先式的多任务系统。Windows95/Windows98/NT就是这种系统。

3:曾有这样的疑问,为什么很多资料中都有关于windows中的While(getmessage(&msg,Null,0,0)){..}消息循环不占用CPU的说法?今天特有关此事查了一下资料,原来是这样子啊! 
说,其实这里的while(){}循环是占用cpu的,只是getmessage()是一个阻塞型的函数,当消息队列中没有消息时,它会检查确认,当确认消息队列为空时,则进行V操作,从而使线程外于阻塞状态,不被激发,另外我们知道外于sleep状态的线程是不占cpu的,是故当getmessage无返回值时,while()也不执行。整个线程被阻塞,从而不占用CPU资源。 
当Winows程序启动时,会注册一个窗口类,注册的窗口类中包括当前窗口的风格、消息处理函数等等。然后,程序创建一个该注册窗口类的主窗口,接着,显示这个主窗口并进入到消息循环。在消息循环中,将不断地从窗口自身的消息队列中读取消息,并调用注册的窗口消息处理函数对不同的消息进行处理。

关于Windows中的系统消息循环占用CPU的疑问

GetMessage函数是一个阻塞型的函数,当消息队列中没有消息时,GetMessage会处于阻塞状态。一旦有消息到达,进程会被唤醒,GetMessage马上返回。实现时,使用了一个信号量, GetMessage函数在确定没有消息可读时,对这个信号量进行一个V操作,从而使线程阻塞。而PostMessage、SendNotifyMessage、SendSyncMessage等任何一个发送消息函数在发送完消息之后,都会读取这个信号量的值,当发现这个值等于零时,即表示读消息的线程当前已阻塞,这时就会作一次P操作,来唤醒睡眠的线程。

GetMessage与PeekMessage的区别

PeekMessage 返回 TRUE 的条件是有消息,如果没有消息返回 FALSE 
GetMessage 返回 TRUE 的条件是有消息且该消息不为 WM_QUIT 
   返回 FALSE 的条件是有消息且该消息 为 WM_QUIT

GetMessage不将控制传回给程序,直到从程序的消息队列中取得消息,但是PeekMessage总是立刻传回,而不论一个消息是否出现。当消息队列中有一个消息时,PeekMessage的传回值为TRUE(非0),并且将按通常方式处理消息。当队列中没有消息时,PeekMessage传回FALSE(0)。 
这使得我们可以改写普通的消息循环。我们可以将如下所示的循环:

while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ;

替换为下面的循环:

while (TRUE) { if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break ; TranslateMessage (&msg) ; DispatchMessage (&msg) ; } else { // 完成某些工作的其它行程序 } } return msg.wParam ;

注意,WM_QUIT消息被另外挑出来检查。在普通的消息循环中您不必这么作,因为如果GetMessage接收到一个WM_QUIT消息,它将传回0,但是PeekMessage用它的传回值来指示是否得到一个消息,所以需要对WM_QUIT进行检查。 
如果PeekMessage的传回值为TRUE,则消息按通常方式进行处理。如果传回值为FALSE,则在将控制传回给Windows之前,还可以作一点工作(如显示另一个随机矩形)。 
(尽管Windows文件上说,您不能用PeekMessage从消息队列中删除WM_PAINT消息,但是这并不是什么大不了的问题。毕竟,GetMessage并不从消息队列中删除WM_PAINT消息。从队列中删除WM_PAINT消息的唯一方法是令窗口显示区域的失效区域变得有效,这可以用ValidateRect和ValidateRgn或者BeginPaint和EndPaint对来完成。如果您在使用PeekMessage从队列中取出WM_PAINT消息后,同平常一样处理它,那么就不会有问题了。所不能作的是使用如下所示的程序代码来清除消息队列中的所有消息:

while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) ;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgzwff.html