Windows的消息队列是基于线程的。
消息队列,消息循环:
线程是程序串行执行的最小单位。
一个典型的Win32项目(不是MFC项目,只有一个窗口的项目),其中的消息循环会使用如下代码实现:
//代码段1
MSG msg
BOOL bRet;
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)GetMessage()是取得消息,如果没有消息,线程阻塞在这里,不占用CPU。
DispatchMessage()是将消息分发,分发到所有在这个线程中创建的窗口的窗口处理函数中去。 如果不需要分发消息,就不需要调用DispatchMessage(),例如线程中没有窗口的情况。
线程消息循环:
实际上,任何线程只要调用了上述代码段1中的代码,就已经实现了消息循环的功能。更进一步,其实只要调用GetMessage()函数就可以了。
即:
//代码段2
BOOL bRet; MSG msg;
while( (bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
if (bRet == -1 || WM_QUIT == msg.message){
// handle the error and possibly exit
break;
}
}
在工作线程中,只要有代码段2,就可以实现消息循环的功能了。
这是一个很方便的线程间异步通信的机制。给线程发消息用PostThreadMessage()。为什么去掉了DispatchMessage()呢,因为一般情况下,在工作线程中是不需要创建窗口的,不需要分发到窗口中去处理,能从线程的消息队列里取得消息就足够了。
如果设计线程的初衷为:当某条件发生时,让工作线程开始工作,一直将工作完成,之后挂起,等待新条件的发生,等待时不占用CPU资源。 那么代码段2所展示的机制就能很好的完成这样的功能。 而且可以使多个工作线程都用同样的机制实现,彼此间协同工作,加之某种资源共享机制,可以实现一个异步的消息处理链。
模态对话框:
消息循环可以有多个,可以在上一级消息循环的某个消息的处理过程中,局部创建一个消息循环,模态对话框就是采用这种机制创建出来的。
一个线程可以有多个消息循环,并行的消息循环显然没有意义,多个就是在消息循环中嵌套消息循环。
如代码段1中的DispatchMessage函数,将消息派发到窗口的消息处理函数中,WndProc1()。
现在假设在WndProc1()中创建一个消息循环,并且只取得这个窗口本身的消息 GetMessage(&msg, hWnd, 0, 0),不必Dispatch了,因为已经找到了目标窗口,然后用这个窗口真正的消息处理函数去处理。 这样模态对话框存在时,处理了所有的窗口消息,创建模态对话框的窗口就一直得不到处理消息的机会,模块对话框就始终处于最上层,直到其主动退出。
当然,对模态对话框的这种解释是简化了的,实际过程可能复杂的多,取得的窗口消息至少要包含所有的子窗口的消息,也需要Dispatch到相应的子窗口,等等。但是最基本的机制应该就是这样的。