PeekMessage究竟做了什么?

1.UI线程

2.工作线程

把Delphi里TThread的WaitFor函数转化成C++代码,就会是下面这个样子。

  1. BOOL TThread::WaitFor(HANDLE hThread)
  2. {
  3. MSG msg;
  4. HANDLE handle[1];
  5. handle[0] = hThread;
  6. DWORD dwWaitResult = 0;
  7. do
  8. {
  9. // This prevents a potential deadlock if the background thread
  10. // does a SendMessage to the foreground thread
  11. if (dwWaitResult == WAIT_OBJECT_0 + 1)
  12. PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);
  13. dwWaitResult = MsgWaitForMultipleObjects(1, handle, false, 1000, QS_SENDMESSAGE);
  14. if (dwWaitResult == WAIT_FAILED)
  15. return FALSE;
  16. if (dwWaitResult == WAIT_TIMEOUT)
  17. {
  18. TerminateThread(hThread, 0);
  19. return FALSE;
  20. }
  21. }
  22. while (dwWaitResult != WAIT_OBJECT_0);
  23. return TRUE;
  24. }

使我疑惑的是这两行代码

  1. if (dwWaitResult == WAIT_OBJECT_0 + 1)
  2. PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);

如果注释所讲是真的,那究竟在哪里处理了其它线程用SendMessage发送过来的消息呢?于是我翻MSDN,查PeekMessage函数,它有这样的解释:

“The PeekMessage function dispatches incoming sent messages, checks the thread message queue for a posted message, and retrieves the message (if any exist).”

我用的是MSND2005,好像再早些的版本里并无“dispatches incoming sent messages”这句。光看这样的注释,实在是太晦涩了些。想起我原来好像发过个讨论这问题的帖子,翻了下发帖记录,还真有,见http://topic.csdn.net/u/20070824/14/d0c96e50-6348-49d3-98e4-9fcc9ead5fdd.html。我当时找到的答案是这样的:

“找到答案了。答案在<<Programming Applications for Microsoft Windows>>第26章的Waking a Thread一节.

The Algorithm for Extracting Messages from a Thread ‘s Queue
...

1. If the QS_SENDMESSAGE flag is turned on, the system sends the message to the   proper window procedure. Both the GetMessage and PeekMessage functions handle this processing internally and do not return to the thread after the window procedure has processed the message; instead, these functions sit and wait for another message to process.

我试着翻译一下:如果QS_SENDMESSAGE标志位有效,系统发送消息(即其它线程通过SendMessage发送过来的消息)到对应的窗口过程。GetMessage和PeekMessage函数在内部进行这样的处理,一直等到窗口过程处理完之后才会返回。也就是说,这些函数(GetMessage和PeekMessage)坐下来等到其它的消息处理完。”
   
书本里的解释已经很清楚详细了,我当时的译文有错误,原文是说GetMessage和PeekMessage调用窗口过程处理完SendMessage发送过来的消息后,还会继续坐下来等自己消息队列里的消息。

理论有了,结合着看看上面WaitFor的代码。MsgWaitForMultipleObjects的最后一个参数QS_SENDMESSAGE指明了如果其它有其它线程用SendMessage向本线程的窗口发送消息,MsgWaitForMultipleObjects就会立即返回,返回值为WAIT_OBJECT_0 + nCount(本例中nCount值为1),接下来就轮到PeekMessage登场了。

PeekMessage其实做了两件事,一件是把收到的消息标示为旧消息。见MSND里对MsgWaitForMultipleObjects返回值的解释:

“Functions such as PeekMessage, GetMessage, and WaitMessage mark messages in the queue as old messages.”

另一件就是把SendMessage发送过来的消息dispatch到窗口过程。下一次调用MsgWaitForMultipleObjects时队列里便没有新消息了。

那变旧的消息还在队列里吗?答案是不在。因为用SendMessage发送过来的消息根本就不会进应用程序的消息队列。在PeekMessage调用窗口过程处理完它时,它便消失了。而我们也很轻松的就知道,SendMessage函数把QS_SENDMESSAGE这个标志turn on了,PeekMessage和GetMessage还有WaitMessage把这个标志turn off了,把QS_SENDMESSAGE标志turn off的过程就是把消息变旧的过程。

时间: 2024-11-11 06:40:29

PeekMessage究竟做了什么?的相关文章

异步编程系列第05章 Await究竟做了什么?

p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提高下英文,用我拙劣的英文翻译一些重要的部分,纯属娱乐,简单分享,保持学习,谨记谦虚. 如果你觉得这件事儿没意义翻译的又差,尽情的踩吧.如果你觉得值得鼓励,感谢留下你的赞,愿爱技术的园友们在今后每一次应该猛烈突破的时候,不选择知难而退.在每一次应该独立思考的时候,不选择随波逐流,应该全力以赴的时候,不选择尽力而

为什么 java wait/notify 必须与 synchronized 一起使用,jvm究竟做了些什么

这个课题提出来的是原先的线程并发解决的思路.目前解决线程并发,可以是lock接口结合condition  并发问题一直以来就是线程必不可少的话题. java 是第一个内置对多线程支持的主流编程语言.在Java5之前,对多线程的支持主要是通过对块结构的同步实现的(synchronized配合wait,notify,notifyAll),Java5引入了java.util.concurrent包,提供了对多线程编程的更高层的支持. 今天我们来说说.java中,线程提供我们解决并发.同步的方法 通常可

网管用了四个月薪资从6K到18K,究竟做对了哪一点?

作为互联网的幕后英雄,Linux运维工程师长期隐匿在大众认知范围之外,关于运维的讨论仍旧是一片无人涉足的荒漠.在某知名行业研究调查结果中,非互联网从业者对于运维相关问题的回复有三个高频词汇是:不知道.没听过.网管.当调查人员告诉他们科幻电影中展示***高超技巧时的命令行界面,正是大多数运维工程师每日工作环境时,他们发出极其一致的惊叹.相对于普罗大众的一无所知,技术圈对运维的态度则更偏向于黑色幽默.相较于开发等工作岗位,7*24小时待命的运维工程师总是默默无闻作为守护者,当然同时还要接受"背锅侠&

select count(*) 底层究竟做了什么?

阅读本文大概需要 6.6 分钟. SELECT COUNT( * ) FROM t是个再常见不过的 SQL 需求了.在 MySQL 的使用规范中,我们一般使用事务引擎 InnoDB 作为(一般业务)表的存储引擎,在此前提下,COUNT( * )操作的时间复杂度为 O(N),其中 N 为表的行数. 而 MyISAM 表中可以快速取到表的行数.这些实践经验的背后是怎样的机制,以及为什么需要/可以是这样,就是此文想要探讨的. 先来看一下概况: MySQL COUNT( * ) 在 2 种存储引擎中的部

深入理解select count(*)底层究竟做了什么

SELECT COUNT( * ) FROM t是个再常见不过的 SQL 需求了.在 MySQL 的使用规范中,我们一般使用事务引擎 InnoDB 作为(一般业务)表的存储引擎,在此前提下,COUNT( * )操作的时间复杂度为 O(N),其中 N 为表的行数. 而 MyISAM 表中可以快速取到表的行数.这些实践经验的背后是怎样的机制,以及为什么需要/可以是这样,就是此文想要探讨的. 先来看一下概况: MySQL COUNT( * ) 在 2 种存储引擎中的部分问题: 下面就带着这些问题,以

idea git revert 究竟做了啥

git里面实现撤销commit 这个据我目前所知,有至少4个途径可以做到 1.git reset 2.git revert 3.git rm –cached 4.git checkout 这个可以参考这个 https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting   idea 如何实现的 git revert 是如何实现的? 10:00:04.294: cd D:\workspace\idea\use

Linux从按下电源到屏幕出现命令行究竟做了什么——linux mingetty命令

第一部分:内核的引导(核内引导) 第二部分:运行init及系统初始化 init程序 需要读取配置文件/etc/inittab.inittab是一个不可执行的文本文件,它有若干行指令所组成. 该文件决定了系统的启动级别(1,2,3,4,5). inittab中有这样一行si::sysinit:/etc/rc.d/rc.sysinit(调用执行/etc/rc.d/rc.sysinit,这个脚本中有很多小功能). 第三部分:启动对应运行级别的守护进程 在rc.sysinit执行后,将返回init继续其

当我们按下电源键,Android 究竟做了些什么?

一.启动电源及系统启动 系统从 ROM 中开始启动,加载引导程序到 RAM ,然后执行. 二.引导程序 引导程序是 Android 操作系统开始运行前的一个小程序,因此它需要针对特定主板与芯片,并不是 Android 操作系统的一部分.引导程序是 OEM 厂商或运行商进行加锁.限制的地方. 1 两个阶段 检测外部 RAM 以及为第二阶段加载程序 设置网络.内存等,搭建内核运行环境(为了达到特殊目的时,引导程序可以根据配置参数或者输入数据来设置内核) 2 引导程序的加载器 Android引导程序可

三年完成三轮融资,EasyStack到底做对了什么?

(上图为EasyStack公司创始人兼CEO陈喜伦) 刚进入2017年的第10天,就传来OpenStack创业公司EasyStack完成C轮融资的消息,融资额折算成美元为5000万美元.自2014年2月创立公司以来,EasyStack可以说保持每年完成一轮融资的速度:2014年8月完成由蓝驰创投领投的200万美元A轮融资,2015年5月完成由如山创投领投的1600万美元B轮融资. EasyStack公司创始人兼CEO陈喜伦透露,C轮在2016年7月底启动,当年9月锁定意向.10月开始走流程,并于