多线程的问题(疑惑)

shuangyuzad 2005-03-24 12:09:14
大家试过这个例子吗
http://www.vchelp.net/vchelp/zart/2types_thread.asp?type_id=28&class_id=1&cata_id=2&article_id=57&search_term=
为什么新建的一个UI线程,在这个线程里面创建的窗口,当主线程出于busy loop时,窗口也只能响应wm_timer的消息其他的消息都不能响应,不是在win32中每一个线程都有一个自己的消息对列吗,就主线程处于忙碌,另一个线程里创建的窗口的消息应该由这个线程来处理的不应该没有响应的,我试过如果在主线程的InitInstance时创建新UI线程而不是在主线程的对话框点击按钮后创建,新建的线程里的窗口在主线程busy loop的时候就会有响应,这些是为什么呢,望高手解答
...全文
269 33 打赏 收藏 举报
写回复
33 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
AntonlioX 2005-05-21
up
  • 打赏
  • 举报
回复
shuangyuzad 2005-04-03
因为系统认为T2.W2是主窗口了,你去点它,系统不再对T1.W1做什么。直接active T2.W2了。

你的意思好像是一个进程里如果点击主窗口,系统就会直接去active,而不必去nactive当前的窗口,但如果我是在照原来的例子不变(T1.W1是住窗口),然后在T2.W2里buse loop,T1.W1照样不能active阿
  • 打赏
  • 举报
回复
cut9 2005-04-03
我再给你讲讲16位Windows情况下,微软推荐的做法吧。微软推荐在busyloop里头调用 yield.
yield是让CPU出让一部分空闲,并且窗口处理自己的消息。32位情况下,yield已经作废。
pumpmessage是微软的推荐做法。
建议你先多看看MSDN多查阅资料,多做实验,然后我们基于这个话题再讨论。
  • 打赏
  • 举报
回复
cut9 2005-04-03
somexing(张星星), 没有取消busyloop。
之所以要pumpmessage,是要窗口去处理他应该处理的消息。pumpmessage里头
调用了GetMessage.和dispatchMessage.
如果不让窗口去处理消息的话,任何发给窗口的消息,窗口都不会反映的,包括WM_CLOSE.
PumpMessage是正确的解决办法。

要想马儿长的好,又要马儿不吃草,不要陷入这个逻辑怪圈。




  • 打赏
  • 举报
回复
gnixemos 2005-04-03
. 无论何种情况下,如果在T1.W1.busyloop里头调用 PumpMessage(),t1 窗口也是可以响应消息了

这样的解决方案等于就是取消了 busyloop


所以还是没有解决

  • 打赏
  • 举报
回复
gnixemos 2005-04-01
说了这么大段 ,怎么在点击创建一个新thread窗口后能在主窗口busy时候能响应键盘消息还是没有解决

  • 打赏
  • 举报
回复
cut9 2005-04-01
-----------------------------------------------------------------------------------------
说了这么大段 ,怎么在点击创建一个新thread窗口后能在主窗口busy时候能响应键盘消息还是没有解决
-----------------------------------------------------------------------------------------
看清楚了

"刚洗完澡,补充一下:
1. 无论何种情况下,如果在T1.W1.busyloop里头调用 PumpMessage(),问题得到解决,也就是 T2.W2
能够正常收到所有消息,比如MOUSE, KEY.(验证过)
"

解决了吗?

  • 打赏
  • 举报
回复
cut9 2005-03-31
MSDN, 查询关键字:Q96006

Win32给每个线程提供一个 线程的private input queue 来保存 (mouse, key) 的输入。

  • 打赏
  • 举报
回复
cut9 2005-03-31
刚做了个实验,在 T1.W1.busyloop里头给T2.W2 Post 一个 Left Button Down 消息,T2.W2可以
正常处理。
  • 打赏
  • 举报
回复
cut9 2005-03-31
又想了想,这个假设还有点问题。本着严格的态度,欢迎讨论!
  • 打赏
  • 举报
回复
cut9 2005-03-31
----------------------------------------------------------------------------------------
新的要被激活的窗口将会因为阻塞而等待. 系统确定哪个窗口是应用程序的主窗口,是看那个线程先被
启动而不是看哪个窗口先被创建。这就是为什么楼主在 "主线程的InitInstance时创建新UI线程就没有任何问题"
的原因。因为系统认为T2.W2是主窗口了,你去点它,系统不再对T1.W1做什么。直接active T2.W2了。
可也是主线程先被启动阿??
-----------------------------------------------------------------------------

主线程后进入消息循环。T2先进入消息循环。
  • 打赏
  • 举报
回复
shuangyuzad 2005-03-31
那个例子窗口T2.W2无限循环,主窗口T1.W1也会没反应阿
  • 打赏
  • 举报
回复
shuangyuzad 2005-03-31
新的要被激活的窗口将会因为阻塞而等待. 系统确定哪个窗口是应用程序的主窗口,是看那个线程先被
启动而不是看哪个窗口先被创建。这就是为什么楼主在 "主线程的InitInstance时创建新UI线程就没有任何问题"
的原因。因为系统认为T2.W2是主窗口了,你去点它,系统不再对T1.W1做什么。直接active T2.W2了。
可也是主线程先被启动阿??
  • 打赏
  • 举报
回复
shuangyuzad 2005-03-31
多谢
  • 打赏
  • 举报
回复
cut9 2005-03-31
关于线程怎么从队列取消息,关键是 GetMessage.
贴主结贴吧! 然后我贴出 GetMessage汇编的解析
  • 打赏
  • 举报
回复
cut9 2005-03-31
先结贴吧 ^@^
  • 打赏
  • 举报
回复
cut9 2005-03-31
多谢楼上:) 例子我看了,作者说的我也看了。作者要是说清楚了问题的本质,楼主
是不会发问的了。

继续:

如果把T1.W1换成mainframe. 情况还有点不一样
实验8:
前提:把T1.W1换成mainframe.
实验步骤重复实验1
发现第6步,T2.W2的timer停止,不继续更新.T2.W2也没有产生mouse down 消息.
跟踪,发现 在mouse down 的时候,T2.W2.WinProc 处理一个WM_MOUSEACTIVE消息,并且要返回 WA_ACTIVE ( =1)
查询MSISDN,在mouse down的时候,系统要察看将要active哪一个窗口, 直到找到合适的窗口并且激活它.
如果把WinProc的返回改成 WA_INACTIVE (=3),那么在第6步发现 T2.W2.Timer 继续更新,T2.W2收到
mouse left button down 消息并且Message Beep.
看来如果返回WM_ACTIVE(=1),系统激活T2.W2并且de-active T1.W1.但是T1.W1在无限循环,deactive
T1.W1受到阻塞,不能返回,那么就发生Timer停止,没有后续mouse down消息了。

考虑T1.W1是主窗口,继续跟踪,发现在T2.W2.WinProc处理 WM_MOUSEACTIVE并且返回 wA_ACTIVE的时候,
T1.W1收到一个消息,定义为 10进制的847.查询windows消息定义没有找到此消息定义。怀疑是
系统企图通知T1.W1什么,比如 deactive.

关于应用程序mouse down,怎么样找个窗口激活,请查阅MSISDN.总之,系统要先deactive 原来的,再激活新的。



总结 (version 0.5):
T1,T2,是分开运行并有自己的消息循环,消息被发送给各自的window. 如果window是空闲,它将处理消息。
在mouse down 的时候,系统要寻找合适的window激活,如果主窗口无限循环(忙),那么
新的要被激活的窗口将会因为阻塞而等待. 系统确定哪个窗口是应用程序的主窗口,是看那个线程先被
启动而不是看哪个窗口先被创建。这就是为什么楼主在 "主线程的InitInstance时创建新UI线程就没有任何问题"
的原因。因为系统认为T2.W2是主窗口了,你去点它,系统不再对T1.W1做什么。直接active T2.W2了。

至此,楼主关于多线程的疑惑解决。问题衍生为系统确定主窗口的问题.
关于,top level window,主窗口,有待进一步研究。
  • 打赏
  • 举报
回复
hushuangyan74 2005-03-31
那个例子里面已经说了!
  • 打赏
  • 举报
回复
cut9 2005-03-31
实验5:使T2.W2是child window,点 T1.W1.ButtonLoop 进入无限循环

前提:直接改T2.W2风格为child window. 注意,在Create(W2)的时候是没有指定parent window的。
实验步骤:重复实验1
第4步,发现T2.W2直接成了T1.W1的子窗口。因为并没有指定 T2.W2的parent window,Win32怎么就
自己指定T1.W1是T2.W2的父窗口了呢?
其他现象一样.
结论e:后创建的线程T2,T2试图创建child window的时候,系统自动找到比T2先创建的T1,并把T1.W2
作为T2.W2的parent window.

实验6:使T2.W2是child window,点 T2.W2.ButtonLoopT1 进入无限循环
前提如实验5.
步骤为重复实验3
第4步,和实验5一样,发现T2.W2直接成了T1.W1的子窗口。
在第5步之后,T2.W2.Timer()直接停止,没有接着更新.
结论f: 如果在child window点button使parent window 进入无限循环(从而child window是active window),
T1.W1和T2.W2都不产生mouse down 消息。

实验6:使T2.W2是child window,先创建T2
前提如实验5.
实验步骤为重复实验4.
发现第3步程序报错。大致为没有parent window.
结论g: 如果T2先被创建,尽管T1后被创建,T1.W1比T2.W2先创建,在创建T2.W2的时候,系统仍然
找不到合适的parent window. 看来系统确定 top level window 是考虑哪个线程先被创建,而不是
哪个窗口先被创建。

帮忙啊:连续跟3次贴就不能接着跟了,请看到的朋友帮忙跟一下,我就可以接着发了,谢谢!
  • 打赏
  • 举报
回复
cut9 2005-03-31
请先看完我上面的回贴,现在基于我上面的回贴继续。
先给出测试环境的伪码定义:
进程P = {线程T1, 线程T2}
T1 = {Init(), W1}
T1.Init =
{
Create(W1);
while( T1.MessageLoop() )
{
DispatchMessage(W1);
}
}

T1.W1 = {ButtonCreateT2, ButtonCreateT2W2, ButtonLoop, OnLoop()}
T1.ButtonCreateT2 = {Create (T2); }
T1.ButtonCreateT2W2 = { PostMessage(T2, WM_THMSG_NEWWINDOW)};
T1.W1.OnLoop = {近似无限循环}

解释:T1运行T1.Init. T1.Init创建模式对话框W1, 并且进入T1消息对列循环,并把消息发送给W1.
如果用户在T1.W1上头点ButtonCreateT2,T2启动
如果用户在T1.W1上头点ButtonCreateT2W2,T2收到WM_THMSG_NEWWINDOW并且创建T2的窗口W2
如果用户在T1.W1上头点ButtonLoop, W1进入T1.W1.OnLoop无限循环。

T2 = {Init(), OnCreateNewWindow(), W2}
T2.Init = {return TRUE;}
T2.OnCreateNewWindow[前提条件: 收到WM_THMSG_NEWWINDOW]
{
Create(W2);
Show(W2);
}

T2.W2 = {A Modeless Dialog,Timer(), OnMouseLeftButtonDown(), ButtonLoopT1, OnButtonLoopT1()}

T2.OnMouseLeftButtonDown() = {MessageBeep;}
T2.W2.OnButtonLoopT1() =
{
PostMessage(T1.W1, WM_LOOP);
}
解释:T2线程,分2步。T2.Init直接返回TRUE并且进入消息循环。当T2收到WM_THMSG_NEWWINDOW
后创建窗口W2. 在W2上头,有Button叫ButtonLoop,当用户点button时,W2发送WM_LOOP给
T1.W1,使T1.W1进入近似无限循环。

实验1:原始实验
1. P启动
2. T1.Init
3. 点 T1.W1.ButtonCreateT2, T2启动
4. 点 T1.W1.ButtonCreateT2W2, T2.W2被窗口创建,Timer开始计时更新
5. 点 T1.W1.ButtonLoop, T2.W2.Timer继续更新。
6. 在 T2.W2 上面点鼠标,T2没有 MessageBeep.说明没收到 Mouse left button down消息

实验2:手动发送Mouse Left Button Down 消息给T2.W1
步骤:
修改 T1.W1.OnLoop 为
{
while(SleepAndLoop)
{
PostMessage(T2.W2, mouse left button down);
}
}
在实验1的到第5步,发现T2.W2有MessageBeep,即T2.W2收到 mouse left button down.
结论a: 尽管T1.W1无限loop,T2仍然正常工作并且处理消息。
结论b: 在T1.W1无限循环的时候,在T2.W2上头mouse down,没有mouse down消息发送给T2.W2. 注意,是没有消息。
如果有消息发送给T2.W2, T2.W2是能处理的.

实验3:在T2.W2上使T1.W1 无限循环
1. P启动
2. T1.Init
3. 点 T1.W1.ButtonCreateT2, T2启动
4. 点 T1.W1.ButtonCreateT2W2, T2.W2窗口被创建,Timer开始计时更新
5. 点 T2.W2.ButtonLoopT1, T1进入OnLoop无限循环,但T2.W2.Timer继续更新。
6. 在 T2.W2 上面点鼠标,T2有 MessageBeep.说明收到 Mouse left button down消息
结论c: 在T2是活动窗口(active window)的时候,在T2上头mouse left button down, T2可以收到 mouse 消息,
尽管T1在无限循环。
所以结论b应该是:
结论b1: 在T1.W1无限循环并且是活动窗口的时候,(因为点T1.W1.ButtonLoop使T1.W1活动)
在T2.W2上头mouse down,没有mouse down消息发送给T2.W2. 注意,是没有消息。
如果有消息发送给T2.W2, T2.W2是能处理的.

实验4:在P入口创建T2
步骤:
1. P启动
2. T1.Init,其中,T1.Init改成
T1.Init()
{
Create(T2);
Create(W1);
while( T1.MessageLoop() )
{
DispatchMessage(W1);
}
}
3. T1.W1.OnCreateT2W2
4. T1.ButtonLoop
这时候,在T2.W2上头mouse down,发现 T2.W2 MessageBeep.
结论d:如果T2先被创建,即使T2.W2后于T1.W1创建,在T2.W2上头mouse down,T2能产生 mouse down消息。不管
它是不是活动的。

  • 打赏
  • 举报
回复
加载更多回复(13)
相关推荐
发帖
进程/线程/DLL

1.5w+

社区成员

VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
帖子事件
创建了帖子
2005-03-24 12:09
社区公告
暂无公告