你(可能)不知道的
和Windows消息系统打过交道的人都会知道:GetMessage和PeekMessage这两个API会从窗口的消息队列中检索消息,这些消息时由DispatchMessage分发到窗口的。
大部分人也知道:GetMessage和PeekMessage也会自己分发不进入消息队列的消息。(所有挂起的非队列消息将会被分发,然后只有第一个进入队列的消息会被返回)
但是大多数人不知道的是:SendMessage也会分发消息。
如果线程T1发送消息给一个属于线程T2的窗口,则T1线程会进入睡眠状态直到接收消息的线程处理了这个消息。但是,如果有其他人也发送一个消息到线程T1,则T1则会被唤醒并处理消息,然后会返回到睡眠状态。
为什么这样设计?
Well,当两个线程T1和T2一起协同工作的时候,很有可能发生的场景是:线程T1向线程T2发送消息,同时,当线程T2返回响应给T1之前它就发送消息给T1。因此,线程T1必须准备好接收线程T2发来的消息。
举个例子,线程T1可能发送一个消息,说:”请告诉你所知道的关于X的一切。” 线程T2接着会发送一个消息给线程T1,说:”这个是一个X”,然后继续发送另一个消息:说:”这个是另一个X”,以此类推,直到它将所有关于X的信息告诉给线程T1。
这个时候,线程T1在原始消息返回的时候,它就知道已经收到了所有线程T2发来的关于X的信息。这个循环往复的过程,就是DDE服务的运行原理。
另外一个例子
线程T1发送一个消息给T2,然后线程T2在完成消息的处理之前,还需要请求线程T1给予某种帮助,这其实没有听起来那么奇怪。因为你也会做类似的事情,具体来说,就是当你通过发送消息给控件来响应WM_NOTIFY消息的场景,控件就是WM_NOTIFY消息的发送者。(举个例子,你可能通过向控件发送LVM_GETITEM以获取被激活的条目信息,来响应收到的LVN_ITEMACTIVATE通知消息)
所以,请记住:当你发送消息的时候,就会存在潜在的可重入的可能性。
总结
线程的同步和协同工作,看起来还比较容易操作,但是真正要做到万无一失,还是得深入理解其背后的原理。
最后
Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
本文来自:《When can a thread receive window messages?》
领取专属 10元无门槛券
私享最新 技术干货