对线程间SendMessage的解疑
对线程间SendMessage的解疑
上面说过线程内SendMessage只是简单的调用指定窗口的窗口过程。
而线程间SendMessage时,发送线程不可能直接调用目标窗口的窗口过程,因为发送线程无法运行在接收线程的地址空间中。因此实际过程是发送线程挂起,然后由另外的线程处理消息。过程是:
首先发送的消息被追加到接收线程的发送消息队列中(send-message queue),并设置线程的QS_SENDMESSAGE标志。这个队列跟邮递消息队列(post-message queue,即之前所谓的消息队列)是并列的,之间没有关系。另外还有一个应答消息队列(reply-message queue),这在后面会用到。
之后,如果接收线程已经在执行其它代码,则暂时不会处理该消息。当接收线程进入等待消息时(如调用GetMessage、PeekMessage或WaitMessage),Windows系统首先检查线程的QS_SENDMESSAGE唤醒标志是否设置,如果设置,则系统扫描发送消息队列中消息的列表,并找到第一个发送的消息。
当接收线程等待消息时,系统从发送消息队列中取出第一个消息并调用相应的窗口过程来处理消息。如果发送消息队列中不再有消息,则QS_SENDMESSAGE被关闭。当接收线程处理消息时,调用SendMessage的线程设置成idle状态,并等待一个消息出现在它的应答消息队列中。在发送的消息处理之后,窗口过程的返回值等级到发送线程的应答消息队列中。发送线程被唤醒,取出包含映带消息队列中的返回值,即SendMessage
的返回值。然后发送线程继续执行。
当线程等待SendMessage返回时,基本时处于idle状态。但当其它线程向该线程的窗口发送消息时,系统要立即处理消息,而不用象前一段说过的等待线程调用GetMessage、PeekMessage或WaitMessage时才处理线程间的Send消息。
虽然线程间的非队列(Send)消息也是发送的队列中的,但与post消息有两个主要区别:
1. 队列不同,分别是send-message queue和post-messag queue。
2. 获取消息途径不同。Post型消息是接收线程通过GetMessage获得的;而Send型消息则是通过系统从队列中提取,然后调用该消息的对应窗口进行执行,这个过程在接收线程等待消息时才执行。
参考资料
来自《WINDOWS核心编程》
However, if a thread is sending a message to a window created by another thread, the internal workings of SendMessage are far more complicated.1 Windows requires that the thread that created the window process the window's message. So if you call SendMessage to send a message to a window created by another process, and therefore to another thread, your thread cannot possibly process the window message because your thread is not running in the other
process's address space and therefore does not have access to the window procedure's code and data. In fact, your thread is suspended while the other thread is processing the message. So in order to send a window message to a window created by another thread, the system must perform the actions I'll discuss next.
First, the sent message is appended to the receiving thread's send-message queue, which has the effect of setting the QS_SENDMESSAGE flag (which I'll discuss later) for that thread. Second, if the receiving thread is already executing code and isn't waiting for messages (on a call to GetMessage, PeekMessage, or WaitMessage), the sent message can't be processed—the system won't interrupt the thread to process the message immediately. When the receiving thread is waiting for messages, the system first checks to see whether the
QS_SENDMESSAGE wake flag is set, and if it is, the system scans the list of messages in the send-message queue to find the first sent message. It is possible that several sent messages could pile up in this queue. For example, several threads could each send a message to a single window at the same time. When this happens, the system simply appends these messages to the receiving thread's send-message queue.
When the receiving thread is waiting for messages, the system extracts the first message in the send-message queue and calls the appropriate window procedure to process the message. If no more messages are in the send-message queue, the QS_SENDMESSAGE wake flag is turned off. While the receiving thread is processing the message, the thread that called SendMessage is sitting idle, waiting
for a message to appear in its reply-message queue. After the sent message is processed, the window procedure's return value is posted to the sending thread's reply-message queue. The sending thread will now wake up and retrieve the return value contained inside the reply message. This return value is the value that is returned from the call to SendMessage. At this point, the sending thread continues execution as normal.
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.
因篇幅问题不能全部显示,请点此查看更多更全内容