win32窗口过程与消息处理机制?

binbin 2003-01-12 11:02:45
发现自己还是一知半解.

void __fastcall TForm2::Timer1Timer(TObject *Sender)
{
ShowMessage("");
}
这样的消息处理不会死锁,消息框会不断跳出来,虽然ShowMessage是"阻塞"式的,而用户并不按确定结束它.


void __fastcall TForm2::Timer1Timer(TObject *Sender)
{
while(true)
;
}
必然死锁.为什么?

此外,在多窗口的应用程序中,每个窗口都有自己的窗口过程,为什么其中一个死锁,全部窗口都死掉?在哪里阻塞了?
...全文
341 点赞 收藏 33
写回复
33 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
binbin 2003-01-13
PeekMessage/DispatchMessage在Dll中也有用.
回复
binbin 2003-01-13
如果是在一个DLL函数中执行while会怎么样呢?
如果想在这个while中处理消息会怎么样呢?
Dll有Application->ProcessMessages()吗?
用API如何实现?俺试了PeekMessage/DispatchMessage没有用.
回复
binbin 2003-01-13
Application->ProcessMessages() ;
ProcessMessages() ;隐藏了什么?如果不是CB写的程序,如何实现在循环中处理消息?
PeekMessage和DispatchMessage?

大家试一试在Timer1Timer中改成这样:
....
static int i;
i++;
ShowMessage(i);
while(true)
{
MSG msg;
::PeekMessage(&msg,NULL,0,0,PM_REMOVE);
::DispatchMessage(&msg);
}
....
除了不能正常退出以外,呵呵.
不过,一段时间后N个循环同时进行,结果会怎么样呢?
回复
zywx 2003-01-13
void __fastcall TForm2::Timer1Timer(TObject *Sender)
{
while(true)
Application->ProcessMessages() ;
}


这样就不会死锁,因为在循环的同时处理应用程序的消息
回复
这点很容易理解,当你用ShowModal产生模式对话框后,然后向主窗体发送消息,你会发现对话框没有关闭之前主窗体已经响应了,而不是对话框关闭之后才响应的...

回复
binbin 2003-01-13
俺觉得应该这样理解,消息处理到ShowMessage后,将其他窗口Disable,系统又进入空闲,把Timer1Timer的当前调用挂起,继续处理其他消息.
在while时则无法空闲下来,其他消息无法处理(可是消息还在产生啊),一旦while结束,队列中等待的消息还是会处理(当然有部分被丢弃或合并).
Sleep使当前线程放弃CPU时间,对于主线程讲和while没有区别的,消息也无法处理,是不会再产生第二个Timer1Timer调用的.95533(鼠标垫) 的观点似乎有点错误.

可是系统如何利用空闲时间以及在各个消息的处理中分配CPU时间呢?
"其实了,说白了,Windows程序和DOS程序还是有本质上的相似的。"
俺严重同意,单CPU的机器上一个时间里总是处理一件事情,可是在消息驱动下,事情处理的顺序变得不可知了,试想一个,在ShowMessage的那个Timer1Timer调用开始后,系统跑去处理其他消息了,这时用另一个程序通过EnableWindow将父窗口强制激活,可能会发生什么...
呵呵,可能什么也没发生,也可能程序出错--如果你的程序依赖ShowMessage之类的对话框返回结果来处理的话.

继续讨论!
回复
jishiping 2003-01-13
说来说去,没想到楼主还是没有明白。现和你说件事,在Win95以后,系统是多任务的(多个任务同时在运行),系统的的运行是以线程为基本单位的,就说说系统轮流给各个线程分配CPU时间的。同时线程也是有优先级的,优先级高的,分配的时间多一些。因此一个线程死循环,并不会造成其它的线程也死掉(因为系统仍然会分配时间给其它线程),这就是为什么一个程序死循环时,其它的程序仍然可以运行的原因。而在DOS和Win31时,系统是实时的,单任务的,一个程序死循环,就会造成整个系统死机。所以,一个程序的是否在运行,不会导致整个系统的其它程序的运行,最多只是影响到其它程序分配到的CPU时间的多少。但是,如果一个程序,如果破坏了Windows系统的内核,这个时候才会造成整个系统死机。

我们再来看看 Application->Run()的大概流程(不是全部流程):
Terminated = false;
do
{
if(PeekMessage(Msg, 0, 0, 0, PM_REMOVE))
if(Msg.Message != WM_QUIT)
{
TranslateMessage(Msg);
DispatchMessage(Msg); //这儿执行对应的消息处理函数
}
else
Terminated = true;
}
}while(!Terminated);
从上面可以看出,这个函数本声也是一个循环,它不停的从消息池中取消息,然后执行相关的消息的处理函数。所以,如果在一个消息处理函数中,发生了死循环,那么Application->Run就不会再运行,不会处理消息了,这时整个程序就死了。但是如果在消息处理函数里,程序自己调用PeekMessage等函数,这样整个程序就还会响应消息,就是说,程序还会执行各个消息的处理函数。但是消息处理函数如果一直不返回的话,那么程序的运行,就不会回到Run()这个函数里,因而也就不能结束。
回复
binbin 2003-01-13
完了,刚看了评选要求,时间过了!
我倒!!!
回复
binbin 2003-01-13
俺已经明白了,继续讨论是俺想让牛人们把问题完整地写清楚,争取十大好贴;)
---------------------------------------------------------
DispatchMessage(Msg); //这儿执行对应的消息处理函数
---------------------------------------------------------
是不是消息处理函数不返回,下一条消息就得不到处理?
为什么不是我们的程序去调用窗口过程,而用回调函数的方法?
DispatchMessage后面系统做了什么?
在ShowMessage的时候,DispatchMessage是不是返回了,而while没有返回?

继续讨论!
回复
void __fastcall TForm2::Timer1Timer(TObject *Sender)
{
ShowMessage("");
}
///////////////////////
这段程序不会死锁是正常的,Timer组件事实上封装了SetTimer API 函数.
SetTimer事实上会开启一个定时线程(它和严格意义上的线程的概念不完全相同).所以它是单独运行的.每隔一定的时间个应用程序发送定时消息,进而触发OnTimer消息.而Ontimer事件已经委托给了TForm,所以Ontimer事件并不能使定时器线程停止.也就是说它不是由定时器执行的,而是主窗体.所以每隔固定的时间会执行TForm的Timer1Timer,不点击ShowMessage的OK只会使Timer1Timer不返回,但这不影响下一个Timer事件的执行,怎么会死锁呢.?????

void __fastcall TForm2::Timer1Timer(TObject *Sender)
{
while(true)
;
}
////////////////////////////////
这个如果不死锁我哪才怪呢..
回复
binbin 2003-01-12
但是在前一例中,ShowMessage在用户按确定之前也是阻塞的,Timer1Timer也没退出啊?
回复
当ShowMessage没有返回的时候程序并不是在忙,而是闲着.因为ShowMessage产生的窗口有自己的窗口过程.
这和Sleep是完全不同的.
Sleep消耗的是主线程的时间.主线程当然没有时间去PeekMessage取得定时器消息.
回复
binbin 2003-01-12
这个问题竟然要讨论这么久啊.
___________________________________

似乎还有一此事情没搞清啊!
回复
binbin 2003-01-12
-------------------------------------------------
仅仅是说程序处于空闲(没有代码执行时),才会产生消息,然后将这些消息发送给窗口。如果程序一直在忙,她就不会产生消息了。
_________________________________________________

你改为这个试试:
while(true) {
sleep(10);
}
就不会了,因为cpu不会被撑死.
_________________________________________________
你如果在里面加入sleep使系统cpu空闲,你会发现Timer消息会发出调用另一个Timer1Timer,会被多次运行的.
_________________________________________________
:::不幸的是,俺的测试结果为:Timer消息并没有产生另一个Timer1Timer,难道是俺的CPU不够强劲???
:::如果俺用Sleep(100000)代替ShowMessage,则还是死锁,不会有新的Timer消息被处理.JSP是对的,本程序被锁死了.
-------------------------------------------------
如果程序一直在忙,她就不会产生消息了
:::消息是应用程序本身产生的,还是windows(及相关硬件驱动)产生的?可以试试在程序忙的时候发送消息,很多消息在程序醒过来还是可以处理的.
回复
binbin 2003-01-12
好!
继续讨论!
回复
googoler 2003-01-12
while(true)为真 ,死循环。Timer1Timer跳不出来!

多窗口(MDI) 子窗口信息是由parent窗口发过来的!

-------------------------------------------------------------------
以上所述实属个人胡乱推测,如有雷同,纯属巧合。欢迎各位高手斧正。
仅供参考而已!
回复
to binbin(BCB水王(不提倡大家向俺学习))
/////////////////////////////////////////////////////////
ShowMessage 只是导致用户不能操作其它的窗口,
同意,因为可以从外部EnableWindow激活消息框的父窗口.
但是ShowMessage不返回,调用它的Timer1Timer不是一直在等待吗
//////////////////////////////////////////////////////////
"调用它的Timer1Timer不是一直在等待吗"是的.这个Timer1Timer的确一直在等待.但并不是不能执行下一个Timer1Timer;因为Timer1Timer并不是用临界代码区,当然可以重入.......

你的理解有误.
回复
ShowMessage()后主窗体不能的到焦点,但不是不能响应消息,就这么简单.
而while(1)是永远的占用主线程的cpu时间,当然不能响应其他消息.

..............

回复
这个问题竟然要讨论这么久啊.

:)
回复
jishiping 2003-01-12
上面只是解释了为什么使用ShowMessage时其它窗口为什么用户不能用鼠标操作其它的窗口。至于“为什么while(1);造成自己程序的其它窗口也死掉”,还是没有说清。其实了,说白了,Windows程序和DOS程序还是有本质上的相似的。在DOS下,如果程序执行while(1);,程序就不会往下执行了,而是死在这个死循环里,在Windows下也一样。Windows的消息驱动,仅仅是说程序处于空闲(没有代码执行时),才会产生消息,然后将这些消息发送给窗口。如果程序一直在忙,她就不会产生消息了。对于ShowMessage的窗口,只是用户不能操作其它窗口,而并不是在忙。在显示窗口后,程序就出于空闲状态,等待用户的输入,或者是其它的东西导致的消息。其它导致的消息包括TTimer产生的消息,窗口原先被遮盖,现在显示了需要重画,系统发给窗口的消息,等等。
回复
发动态
发帖子
Windows SDK/API
创建于2007-08-02

1202

社区成员

C++ Builder Windows SDK/API
申请成为版主
社区公告
暂无公告