VB6计时器控件是否会创建单独的线程?

5
VB6的Timer控件在启动时是否会创建一个单独的处理线程?

这个问题在VB6中的后台处理方面有很好的选项。https://dev59.com/t3VC5IYBdhLWcg3w4VX6 - MarkJ
@MarkJ:如果我不想在VB6中陷入困境,使用COM包装的BackgroundWorker线程是否是最简单的解决方案? - CJ7
是的,这应该很容易。不过我自己从来没有做过! - MarkJ
2个回答

7

VB6计时器控件并不是在后台线程上运行的某种繁忙等待循环。它们实际上并没有“运行”。

据我所知,当您将Enabled = True(或更改Interval,如果为0)时,该控件会进行SetTimer()调用。当您将Enabled = False(或将Interval设置为0)时,它会进行KillTimer()调用。

正常的VB6消息循环(当然在UI线程上运行)通过将传入的WM_TIMER消息分派到关联的计时器事件处理程序代码来处理它们。因此,您事件处理程序内部的代码将在UI线程上运行,在退出之前阻止进一步的消息处理。Interval似乎被切片为一个无符号16位值-出于遗留原因(16位VB和Windows)?

像编写在程序中的繁忙等待循环(所有代码都在UI线程上运行)这样的任何内容,当然会阻塞消息处理,从而产生计时器不会“触发”的错觉。由于WM_TIMER是低优先级消息,因此当您将UI线程绑定在一起时,它们不会在消息队列中深度堆叠:

WM_TIMER消息是低优先级消息。 GetMessage和PeekMessage函数仅在线程的消息队列中没有其他高优先级消息时才发布此消息。


Bob,这个的推论是什么?我可以把长时间处理任务(比如长存储过程)放到定时器控件里,然后期望UI响应吗? - CJ7
我同意,计时器对于长时间阻塞操作没有任何帮助。如果您有一个冗长的存储过程,请使用ADO的异步执行选项而不是同步调用。这使得ADO可以使用内部线程来处理处理和等待完成。 - Bob77
@MartinJames:在计时器代码中加入DoEvents是否可以保持UI响应,从而给人多线程的错觉? - CJ7
1
@Bob77,你有这方面的任何参考资料吗?我相信你是对的,但我想看一些官方文档,以便我自己理解这个问题。 - Carl Onager
你看过 http://msdn.microsoft.com/en-us/library/windows/desktop/ms677579(v=vs.85).aspx 以及相关页面,例如 http://msdn.microsoft.com/en-us/library/windows/desktop/ms675083(v=vs.85).aspx 吗? - Bob77

3
不,计时器运行在同一线程中,即 Visual Basic 6 程序的窗口过程。这意味着如果你执行处理器密集型操作,就不能依赖 WM_TIMER 消息被处理。

3
此外,纯VB6实现多线程的方法是创建一个VB6 ActiveX exe并以特定方式进行配置和使用。 - Mafu Josh
@MafuJosh:这与通过互操作使用COM包装的BackgroundWorker对象相比如何? - CJ7
好吧,这不会是一个纯VB6的解决方案,但是这取决于你。除此之外,我不知道了。看起来有很好的例子(http://msdn.microsoft.com/en-us/library/aa719109%28v=vs.71%29.aspx)介绍如何使用BackgroundWorker,所以那可能更容易些。使用ActiveX exe,你基本上需要编写自己的后台工作器。此外,ActiveX exe方法与VB6 IDE更兼容。如果在线程中设置了断点,则.NET线程可能会崩溃(根据该链接)。另外,我没有描述使用ActiveX exe进行线程处理的链接。似乎人们使用两种方式。 - Mafu Josh
@CJ7 我知道你可能已经写好了你的代码,但是在VB6中使用单独的ActiveX EXE来实现多线程比使用包装后台工作者的互操作性要少得多。 - Carl Onager

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接