消息队列是一个由数组结构构成的循环队列,即核心线程对象(__KERNEL_THREAD_OBJECT)定义的KernelThreadMsg数组,为方便阅读,把核心线程对象定义中关于线程消息队列的部分代码列举如下:
KernelThreadMsg数组是一个类型为__KERNEL_THREAD_MESSAGE结构的数组,根据目前的定义,该数组大小是32(在实际代码中,以宏定义MAX_KTHREAD_MSG_NUM替代硬编码的32)。ucAligment是为了实现数据对齐(32bit对齐),ucQueueHeader和ucQueueTail分别指向队列的头部和尾部,其中,ucQueueHeader指向队列的第一个非空元素(若队列非空的话),而ucQueueTail指向了消息队列中第一个空元素(若队列不满的话)。ucCurrentMsgNum则指出了当前队列中消息的个数,如图4-6所示。
图4-6 线程的消息队列
系统中的核心线程可以通过SendMessage函数调用向队列中发送消息,如果队列不满,则消息被存储在ucQueueTail所指向的位置,同时ucQueueTail后移一个元素(指向下一个非空位置),ucCurrentMsgNum增加1,如图4-7所示。
图4-7 线程消息队列的添加操作
线程本身可以调用GetMessage函数,从自己的消息队列中获取消息。若当前消息队列为空,则GetMessage函数阻塞(通过等待一个EVENT核心对象),直到有其他线程向本线程的消息队列中发送消息。若消息队列非空,则GetMessage函数取走ucQueueHeader所指位置的消息,然后ucQueueHeader向后移动一个位置,ucCurrentMsgNum减1,如图4-8所示。
图4-8 线程消息队列的删除操作
队列当前的状态(空或满)可以通过判断ucCurrentMsgNum的大小获得。(www.xing528.com)
lpMsgEvent是一个__EVENT内核对象,该对象用来完成消息操作的同步。在当前Hello China的实现中,GetMessage函数是按照同步操作实现的。即若队列中有消息,则该函数立即返回,并把队列中的消息返回给用户程序;若队列中没有消息,则该函数阻塞,直到有消息到达。阻塞操作就是通过等待该事件对象实现的。下面是GetMessage函数的相关代码。
在上述实现中,GetMessage函数首先判断线程的消息队列是否为空,若为空,则调用lpMsgEvent对象的WaitForThisObject函数等待lpMsgEvent对象。
而lpMsgEvent对象是被SendMessage函数唤醒的,SendMessage函数的相关实现代码如下:
在上述实现中,每向线程队列发送一个消息,就会调用SetEvent函数设置事件对象的状态,这样若当前线程因为调用GetMessage函数阻塞,此时就会被唤醒。
对于线程的消息队列,最后需要解释的就是__KERNEL_THREAD_MESSAGE结构本身了,顾名思义,该结构用来装载具体的消息,定义如下:
wCommand是一个命令字,指出具体的消息类型,比如键盘按下、鼠标按下等,也可以由用户自己定义。wParam和dwParam是两个与wCommand关联的参数,比如,与“键盘按下”这样一个消息相关联,可以是具体被按下的键的ASCII码(可以通过wParam设置)。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。