我正在将一个古老的VB6程序移植到C#/ .Net。我不太了解VB6,我要求它更好地理解它。
旧的VB6程序有一个主要的程序执行过程,但它还有很多事件处理程序,用于套接字事件或定时器事件,以及这些经常操作的共享资源的处理程序,例如,常见的全局变量,每当它们醒来并运行时。
尽管如此,旧程序似乎运行良好。
尝试在C#中执行相同的体系结构是灾难性的,因为套接字或计时器的事件处理程序由系统在与主应用程序线程不同的线程中调用,并导致频繁的异常,例如“调用线程无法访问此对象,因为不同的线程拥有它。“,更不用说更微妙的问题了。我在转换中的大部分工作是重新设计程序以使其成为线程安全的,并且消除了原始程序对全局变量的大量使用。
我的问题是VB6事件处理程序在不同的线程中运行吗?如果是这样的话,VB6怎么会侥幸逃脱呢?除此之外,VB6程序有一个计时器,每4秒钟唤醒一次,操纵一些全局变量并重新入睡,而主程序正在做它的事情。我不明白为什么这不会导致碰撞。
答案 0 :(得分:7)
我的问题是VB6事件处理程序是在不同的线程中运行吗?
常见答案:否。
真实回答:是的,如果你做了令人讨厌的Win32调用来产生更多的线程。正确地做这件事的几率接近于零。我不认为我曾经在实际代码中看到它。
除此之外,VB6程序有一个计时器,每4秒钟唤醒一次,操纵一些全局变量并重新入睡,而主程序正在做它的事情。我无法理解为什么这不会导致碰撞。
当计时器唤醒时,它会在UI的队列中放入一条消息。当UI进入空闲状态时,它会处理消息并在UI线程上运行事件。
如果您使用正确的计时器,您可以在WinForms中执行相同的操作。
答案 1 :(得分:5)
Apartment-Model Threading in Visual Basic
如果你想要坚实的细节,请研究COM中的公寓线程模型。 VB6基本上使用COM,它的内置隐含线程模型将单线程视为消息传递实体。它简化了线程安全性,但是通过基本上将所有方法调用视为排队服务调用,您可以牺牲大量开销。
所有代码基本上都在一个实现COM服务调用的容器中运行。如果您曾经使用过其他语言的VB6编写过的东西,通常可以通过COM与它们进行交互。
VB6事件处理程序是否在不同的线程中运行?
不是真的,因为没有单独的线程。您的代码在单个线程上运行,包含在我上面描述的类似服务的体系结构中。您与之交谈的大部分内容都是其他具有自己公寓的COM对象。所以要来回沟通,当线程互相交谈时,你基本上都在进行RPC调用:你不是直接操纵它们。
除此之外,VB6程序有一个定时器,每4秒钟就会唤醒一次,操纵一些全局变量并重新进入睡眠状态,而主程序正在做它的事情。我无法理解为什么这不会导致碰撞。
“计时器”位于为计时器创建的单独线程上,但是当它调用代码时,保证不会中断任何其他函数,因为函数调用基本上在线程中一次排队。
答案 2 :(得分:0)
对Matt Wilko来说,DoEvents是VB6实现虚拟协作多线程的东西。什么是线程,可以中断运行其他代码的东西。当您使用DoEvents时,您会中断代码的执行,当CPU进行多线程处理时,它会抢占您的代码。效果是一样的。一个由VB6运行时完成,另一个由CPU完成。
效果是一样的。您需要同步访问全局对象和变量。
您的事件处理程序不应该运行太长时间。每个事件都排队并一次运行一个。
多线程VB6的方法是将其他东西放在带有异步模型的COM Exe文件中。 exe完成后回拨。