请教一个PeekMessage的问题

swimmer2000 2007-08-24 02:25:45
一个程序有两个线程,一个为主线程(UI线程),另一个为工作线程。工作线程把取得的数据通过SendMessage发送到主UI线程,进行显示。当用户进行关闭主窗口的操作时,我通过改变标志位(g_bStopEvent)的方式让主线程通知工作线程结束工作。这个程序能够很好的工作,只是我还有些地方不太明白。程序代码如下:

bool g_bStopEvent;
HANDLE g_hWorkThread;
HANDLE hMainWnd;

g_bStopEvent = false;

CMyDialog myDlg;
hMainWnd = myDlg.m_hWnd;

// UI主线程

CMyDialog::OnClose()
{
g_bStopEvent = true;
WaitFor(g_hWorkThread); // 等待工作线程结束
CDialog::OnClose();
}

BOOL CMyDialog::WaitFor(HANDLE hThread)
{
MSG msg;
HANDLE handle[1];
handle[0] = hThread;
DWORD dwWaitResult = 0;

do
{
// This prevents a potential deadlock if the background thread
// does a SendMessage to the foreground thread
if (dwWaitResult == WAIT_OBJECT_0 + 1)
PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE); // 这里
dwWaitResult = MsgWaitForMultipleObjects(1, handle, false, 1000, QS_SENDMESSAGE);
if (dwWaitResult == WAIT_FAILED)
return FALSE;
}while (dwWaitResult != WAIT_OBJECT_0);

return TRUE;
}

// Worker线程
unsigned __stdcall ThreadFunc(void* pArguments)
{
while (g_bStopEvent != false)
{
SendMessage(hMainWnd, WM_COPYDATA...);

}
return 0;
}

问题是: PeekMessage是怎样对工作线程发出的消息进行处理的?
...全文
487 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
swimmer2000 2007-08-24
  • 打赏
  • 举报
回复
谢谢guxingfeiyu(孤星飞雨)的支持.
美丽海洋 2007-08-24
  • 打赏
  • 举报
回复
接受线称有回调函数,就是再回掉的时候处理的
guxingfeiyu 2007-08-24
  • 打赏
  • 举报
回复
你的翻译是对的,找到一些关于PostMessage和SendMessage的信息
=======

PostMessage 和SendMessage的区别主要在于是否等待其他程序消息处理。

PostMessage只是把消息放入队列,不管其他程序是否处理都返回,然后继续执行;而SendMessage必须等待其他程序处理消息后才返回,继续执行。

这两个函数的返回值也不同,PostMessage的返回值表示PostMessage函数执行是否正确,而SendMessage的返回值表示其他程序处理消息后的返回值。

一、当调用SendMessage时,接收消息的线程的QS_SENDMESSAGE标志被设置,系统调用相应的窗口过程来处理这个消息。GetMessage和PeekMessage函数在内部进行这种处理。如果在“发送消息队列”中没有消息了,QS_SENDMESSAGE标志就被关闭。“发送消息队列”中可能有几个Send过来的消息。例如,几个线程同时向一个窗口发送消息。


二、当调用PostMessage时,函数GetMessage或PeekMessage填充传递给它们的Msg结构,函数返回。再调用DispatchMessage,让相应的窗口过程来处理消息。


三、当调用SendMessage时,发送线程和接收线程是同一个线程的时候,SendMessag很简单,只是调用指定窗口的窗口过程。但当发送线程和接收线程不是同一个线程时,麻烦就大了。因为发送线程和接收线程运行在不同的地址空间中,因此不能访问接受线程中相应窗口过程的代码和数据。其实这时发送线程要挂起,当接收线程处理Send过来的消息时,发送线程被设置为空闲(idle)状态。在发送的消息处理完成后,窗口过程的返回值被登记到发送线程的应答消息队列中。发送线程被唤醒,取出包含在应答消息队列中的返回值。这个返回值就是调用SendMessage的返回值,这时,发送线程继续运行。


四、WM_PAINT和WM_TIMER这两个消息的优先级非常低,最低的是WM_TIMER。


五、WM_COPYDATA只能Send,不能Post
swimmer2000 2007-08-24
  • 打赏
  • 举报
回复
do
{
// This prevents a potential deadlock if the background thread
// does a SendMessage to the foreground thread
if (dwWaitResult == WAIT_OBJECT_0 + 1)
PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE); // 这里
dwWaitResult = MsgWaitForMultipleObjects(1, handle, false, 1000, S_SENDMESSAGE);
if (dwWaitResult == WAIT_FAILED)
return FALSE;
}while (dwWaitResult != WAIT_OBJECT_0);

如果线程接收到通过SendMessage发送过来的消息,QS_SENDMESSAGE标志就会被置为有效。
根据上面上面的解释,代码中的PeekMessage就会在内部处理通过SendMessage发送过来的消息。
swimmer2000 2007-08-24
  • 打赏
  • 举报
回复
找到答案了。
答案在<<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)坐下来等到其它的消息处理完。

guxingfeiyu 2007-08-24
  • 打赏
  • 举报
回复
也就是说:
当线程中调用了SendMessage的时候WaitFor的MsgWaitForMultipleObjects接收到一个新的信号,此时dwWaitResult = WAIT_OBJECT_0 + nCount(nCount = 1),然后循环到 if (dwWaitResult == WAIT_OBJECT_0 + 1)
的时候执行PeekMessage,这个函数的目的是设置这个新收到的WINDOWS消息为旧消息,然后再次MsgWaitForMultipleObjects的时候MsgWaitForMultipleObjects会返回说“已经有符合条件的信号了”(因为消息已经是“旧”消息了,注意,消息并没有被处理),从而dwWaitResult = WAIT_OBJECT_0不再满足后面的while条件(dwWaitResult != WAIT_OBJECT_0),WaitFor函数返回。
然后可以执行CDialog::OnClose,从而得以继续执行消息循环。而线程中的SendMessage得以获得返回,从而退出线程。
swimmer2000 2007-08-24
  • 打赏
  • 举报
回复
To guxingfeiyu(孤星飞雨): So?
guxingfeiyu 2007-08-24
  • 打赏
  • 举报
回复
WAIT_OBJECT_0 + nCount
New input of the type specified in the dwWakeMask parameter is available in the thread's input queue. Functions such as PeekMessage and GetMessage mark messages in the queue as old messages. Therefore, after you call one of these functions, a subsequent call to MsgWaitForMultipleObjects will not return until new input of the specified type arrives.
This value is also returned upon the occurrence of a system event that requires the thread's action, such as foreground activation. Therefore, MsgWaitForMultipleObjects can return even though no appropriate input is available and even if dwWaitMask is set to 0. If this occurs, call PeekMessage or GetMessage to process the system event before trying the call to MsgWaitForMultipleObjects again.

swimmer2000 2007-08-24
  • 打赏
  • 举报
回复
我之所以提出这个问题,是因为如果如下的OnClose函数,这个程序就会陷入无限等待。
出现这种情况是因为工作线程的SendMessage正在等待UI线程返回,而此时UI线程又在等待工作线程的结束信号,一个死锁就产生了。
为什么采用PeekMessage和MsgWaitForMultiObjects的方法能够正常工作呢?
是不是PeekMessage除了检测消息队列之外还做了其它的事情?

CMyDialog::OnClose()
{
g_bStopEvent = true;
// WaitFor(g_hWorkThread); // 等待工作线程结束
WaitForSingleObject(g_hWorkThread, INFINITE); // 这样做会陷入无限等待
CDialog::OnClose();
}
guxingfeiyu 2007-08-24
  • 打赏
  • 举报
回复
汗,说错,DispatchMessage是派发消息。
guxingfeiyu 2007-08-24
  • 打赏
  • 举报
回复
DispatchMessage是将消息从消息队列中删除啊...
liotion 2007-08-24
  • 打赏
  • 举报
回复
PeekMessage只是从进程的消息队列里取一个消息,和该消息从哪里发来,取出来怎么处理都没关系。
swimmer2000 2007-08-24
  • 打赏
  • 举报
回复
上面写错了,
PostMessage ==>> DispatchMessage
guxingfeiyu 2007-08-24
  • 打赏
  • 举报
回复
PostMessage?
你不知道PostMessage和SendPessage的异同啊
swimmer2000 2007-08-24
  • 打赏
  • 举报
回复
我知道程序里的PeekMessage有一个作用,就是使MsgWaitForMultiObjects能够正常的工作。
但工作线程发送过来的消息并没有看到地方处理。
由于没有调用PostMessage这样的函数,这个消息应该不会到CMyDialog::WindowProc里面
guxingfeiyu 2007-08-24
  • 打赏
  • 举报
回复
PeekMessage根本不管你是哪里发来的消息,它只检查发到这个窗体的消息是否存在,检查到这个消息要处理的话要调用TranslateMessage来处理。不过从你的代码来看WaitFor中仅仅是检查是否有消息。实际处理还是由Windows主程序(MFC隐藏了Windows主程序的调用)调用了相关函数来处理的。你所能看见的处理实际上是在CMyDialog::WindowProc中(若没有相应的处理,则是MFC处理掉,然后调用相关的回调函数了)。

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧