第五章 走得太远,别忘了回家的路(2) ——《箴言》第三章 Windows运行机理之读书笔记之一

 

第五章 走得太远,别忘了回家的路(2)
——《箴言》第三章 Windows运行机理之读书笔记之一


二、“Message Deadlocks”、大师Charles Petzold与Jeffrey Richter的差异

其实,如果真正明白了消息的处理过程,消息还是有些很不简单的。在一定意义上(如果实事求是之程度与勇气等无可怀疑的话),我想,恐怕MS最有资格发言了,如MS自己一再告诫的“Message Deadlocks”问题:“A thread that calls the SendMessage function to send a message to another thread cannot continue executing until the window procedure that receives the message returns. If the receiving thread yields control while processing the message, the sending thread cannot continue executing, because it is waiting for SendMessage to return. If the receiving thread is attached to the same queue as the sender, it can cause an application deadlock to occur. (Note that journal hooks attach threads to the same queue.)”(Platform SDK: Windows User Interface MSDN2001.10)。一个用SendMessage给其他线程的窗口发送消息的线程需要依赖接收线程的正确处理,如果接受线程不能正确处理这种情形时那么发送线程就将挂起了,这样系统就不是健壮的。

为此MS提供了几种办法来处理这种情形。一方面,MS提供其他一些发送消息的办法来避免这种消息“死锁”的情形,如用SendMessageCallback、SendMessageTimeout和SendNotifyMessage等来给其他线程发送消息。

另一方面,还允许那种因用SendMessage向其他线程发送消息而阻塞的线程,在收到incoming nonqueued messages时可以解除这种阻塞状态,即可以先转去处理这些消息而不用等待接收线程处理完成。

关于SendMessage,我们来看看MSDN(2001.10)上的说法:“If the specified window was created by a different thread, the system switches to that thread and calls the appropriate window procedure. Messages sent between threads are processed only when the receiving thread executes message retrieval code. The sending thread is blocked until the receiving thread processes the message. However, the sending thread will process incoming nonqueued messages while waiting for its message to be processed”(适用于Windows NT 3.1 and later, Windows 95 and later)。现在一个阻塞于向其他线程发送消息之SendMessage的发送线程,可以径直处理其他线程发给自己的Incoming nonqueue messages(即当一个线程既是接收线程又是发送线程的时候,亦即在“however”之后再“however”一次,这个发送线程同时成了接收线程之时),就立即给了刚刚说过的话“Messages sent between threads are processed only when the receiving thread executes message retrieval code”一记响亮的耳光,刚刚说过的这话也就立即失去了它的效力,成了一句空话了。而进一步,如果这个SendMessage本身就是在一个Incoming nonqueue message 的消息处理过程中发送的呢,那么就更成了一句空话了。这时将恐怕又要上映一幕矛和盾的喜剧了。

【测试程序 存在性 Incoming nonqueue message之SendMessage至别线程再受理Incoming nonqueue message】
【下面是两个测试程序,先看第一个:
我们再来看第二个:】



虽说这样解除了阻塞状态,但破坏了SendMessage的同步语义,会引来了其他的问题:这种属于强行夺取Windows事件驱动系统之控制权的行为,破坏了正常的Windows事件驱动系统之控制权的转移机制,发送线程如果正在对Posted消息的处理过程之中,那么此时解除阻塞转而去处理incoming nonqueued messages就可能会引起比阻塞更严重的问题(一种混乱之源:颠覆应用程序的控制逻辑);如果发送线程是在处理其他线程(且假定不是接收线程的较简单情形)发送来的消息(即incoming nonqueued message【s】)的过程中用SendMessage给另外的线程发送消息而阻塞的,那么此时系统将又转而去处理新到来的incoming nonqueued messages么?【Win95 NT3.51 XPsp2上试验正是如此】(这又是另一种混乱之源:颠覆事件驱动系统之控制逻辑)。


我们先来看看Petzold的说法。我没有找到《Programming Windows》的1988年的版本,但先来看看1990年第二版的中文版本《Windows编程》的第一章《何谓Windows程序》,在讲了排队消息和非排队消息的处理之后,Petzold接着说,“这个过程虽然比较复杂,但最幸运的是该复杂性在Windows内部而不在程序中。从窗口过程的角度看,消息以一种有序和同步的方式交往。窗口过程可以处理这些消息也可不予理睬。因此,窗口过程象消息的最终汇合点。几乎所有对窗口有影响的操作都有消息发送到窗口过程。……消息与硬件中断不同。当处理窗口过程中的一个消息时,程序不能被另一个消息中断。仅当窗口过程调用一个函数产生一个新消息时,消息过程在函数返回前处理这个消息。”

再来看看第五版本,其中思想是一贯的。在讲了排队消息和非排队消息的处理之后,Petzold也同样接着说,“This process is obviously complex, but fortunately most of the complexity is Windows' problem rather than our program's. From the perspective of the window procedure, these messages come through in an orderly and synchronized manner. The window procedure can do something with these messages or ignore them.
When I say that messages come through in an orderly and synchronized manner, I mean first that messages are not like hardware interrupts. While processing one message in a window procedure, the program will not be suddenly interrupted by another message.  Although Windows programs can have multiple threads of execution, each thread's message queue handles messages for only the windows whose window procedures are executed in that thread. In other words, the message loop and the window procedure do not run concurrently. When a message loop retrieves a message from its message queue and calls DispatchMessage to send the message off to the window procedure, DispatchMessage does not return until the window procedure has returned control back to Windows.
However, the window procedure could call a function that sends the window procedure another message, in which case the window procedure must finish processing the second message before the function call returns, at which time the window procedure proceeds with the original message. For example, when a window procedure calls UpdateWindow, Windows calls the window procedure with a WM_PAINT message. When the window procedure finishes processing the WM_PAINT message, the UpdateWindow call will return controls back to the window procedure. ”

在Petzold看来,消息不像硬件中断;当窗口过程正在处理一个消息时,程序不能被另一个消息突然中断(当然窗口过程自己调用函数发送另一消息给自己(窗口过程)不在此列的,相当于普通的函数调用,当然在此过程中遵循同样的Petzold规则)。

我们再来看Jeffrey的说法,他的说法,也是一贯的,不同的是,这里是他的一贯性,就是用SendMessage发送消息到其他线程而阻塞时可以被中断的,即可以立即处理Incomming nonqueue messages而不用等待接受线程处理完成。先看《Advanced Windows NT》1993年,Jeffrey云,
“While the receiving thread is processing the message, the thread that called SendMessage is sitting idle. After the message has been processed, the result of the processing is returned and the thread that called SendMessage is resumed so that it can continue execution.
While a thread is waiting for SendMessage to return, it sits basically idle. It is allowed to do one thing, however: If another thread in the system sends a message to a window created by a thread that is waiting for SendMessage to return, the system will process the sent message immediately. The system doesn't have to wait for the thread to call GetMessage or PeekMessage in this case.”

肯定了Incoming nonqueue messages机制,肯定了它正是可以“突然”中断消息处理(系统强行中断正在处理的消息而另外插入其他消息的处理,不同于线程内用SendMessage发送消息的情形)。但立即转到怎样防止发送线程被挂起的办法,不对这个机制赞一词。

“Because the Win32 subsystem uses this method to handle the sending of interthread messages,your thread could possibly hang. Let's say that the thread processing the sent message has a bug and enters an infinite loop. What happens to the thread that called SendMessage? Will it ever be resumed? Does this mean that a bug in one application has the ability to hang another application? The answer is yes!
Four functions allow you to defensively write code to protect yourself from this situation.
The first function is SendMessageTimeout:…”。

再看其第四版(1999年)也基本一样,“While a thread is waiting for SendMessage to return, it basically sits idle. It is, however, allowed to perform one task: if another thread in the system sends a message to a window created by a thread that is waiting for SendMessage to return, the system will process the sent message immediately. The system doesn't have to wait for the thread to call GetMessage,PeekMessage, or WaitMessage in this case.
Because Windows uses this method to handle the sending of interthread messages, it's possible that your thread could hang.For example, let's say that the thread processing the sent message has a bug and enters an infinite loop. What happens to the thread that called SendMessage? Will it ever be resumed? Does this mean that a bug in one application can cause another application to hang? The answer is yes!
Four functions—SendMessageTimeout, SendMessageCallback, SendNotifyMessage, and ReplyMessage—allow you to write code defensively to protect yourself from this situation. The first function is SendMessageTimeout:…”

尽管Jeffrey只讲Incoming nonqueue messages机制可以为发送线程解除阻塞,却绝口不提这一机制的引入对发送线程、整个窗口系统意味着什么,不提及它对窗口系统带来的严重危害【后果】,但肯定了Incoming nonqueue messages机制,肯定了它正是可以“突然”(系统强行中断正在处理的消息而另外插入其他消息的处理,不同于线程内用SendMessage发送消息的情形)中断消息处理,这点与Petzold是不一样的。看前面的MSDN中有关说明及Jeffrey的成书介绍,Jeffrey在这点上正是与MS同步的。我想Petzold不会不知道MS的这些说明,而自始自终坚持自己的观点(我尚未发现Petzold的有关这个问题的其它观点,读者如有知情或发现,敬请告我,谢谢!),或许倒有点耐人寻味吧。

【不知什么原因,到第五版(《Windows via C/C++》2008年)时,在书的Introduction中虽然说“In addition to the new organization and greater depth, I added a ton of new content.”,也对重写部分加以说明,对未触及部分如COM和.NET加以说明,但就是绝口不提这个版本中已对窗口系统这部分剪除的事实,而在第四版中窗口内容整整占了一个部分即第六部分。这大抵不会是无意的疏忽,而倒有点像是刻意的回避。窗口系统已经没有什么(重要的)新玩意可说?Windows XP,Windows 2003,Windows Vista,Windows Server 2008等,我想,它们的窗口系统也不至于(重要的)没有新东西可说罢。此时Jeffrey认为不再属于系统编程范畴?或者不宜再在他的这个系统编程书籍中讲述窗口部分?不得而知。【《Windows System Programming》2004年的第3版和2010年的第4版均无窗口系统内容,早期版本我没有找到。作为MS操作系统内幕的官方代表著作系列,从《Inside Windows NT》(第一版)到《Windows Internals》(第五版)都从未将窗口系统作为一个核心部件(如进程管理、内存管理、IO系统、文件系统等部件)来正式讲述其内部机制(即使把网络部分纳入后也没有窗口系统的一席之地,第二版无网络部分),基本上是在介绍系统体系结构时由于完整性而带上一笔,还有就是第二版至第四版为Windows NT 4.0及其以后的版本将GUI部分移入核心态对内核稳定性等没什么影响(降低)而进行的冗长的辩护(这种声音终于在第五版消停了)等而有所触及。】

【Incoming nonqueue message机制对线程正常执行的影响:如何防止不经意、恶意的干扰线程的正常执行(不谈对SendMessage()被其他线程阻塞的“拯救”)】


三、Window Procedure 与“Reentrant”及鱼死网破

 

(2011.4.1 1214)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值