What was VB6's threading model?

2019-04-11 14:23发布

问题:

I'm porting an ancient VB6 program to C#/.Net. I don't know VB6 very well and I'm asking this to understand it better.

The old VB6 program had a main course of program execution, but it also had lots of event handlers either for socket events or for timer events and the handlers for these often manipulated shared resources, e.g., common global variables, whenever they woke up and ran.

Nonetheless the old program seemed to run OK.

Trying to do this same architecture in C# is disastrous because event handlers for the socket or timers are called by the system in different threads from the main application thread and result in frequent exceptions like "The calling thread cannot access this object because a different thread owns it.", not to mention more subtle problems. Most of my work in the conversion is re-architecting the program to make it thread-safe, and eliminating the original program's heavy use of global variables.

My question is Do VB6 event handlers run in separate threads? If so how did VB6 ever get away with this? Among other things, the VB6 program had a timer that woke up every 4 seconds, manipulated some global variables and went back to sleep, while the main program was doing its thing. I can't understand why this didn't result in collisions.

回答1:

Apartment-Model Threading in Visual Basic

If you want the gritty details, research apartment threading models in COM. VB6 basically uses COM and it's built-in implicity threading models to treat single threads as message-passing entities. It simplifies thread-safety, but underneath you are sacrificing a lot of overhead by basically treating all method calls as queued service calls.

All of your code basically runs in a container that implements COM service calls. If you've ever worked with something written in VB6 in another language, you can interact with them via COM, usually.

Do VB6 event handlers run in separate threads?

Not really, because there aren't separate threads. Your code runs on a single thread, wrapped in the service-like architecture I described above. Most of what you talk to that is threaded is other COM objects which have their own apartments. So to communicate back and forth, you are basically doing RPC calls when the threads talk to each other: you aren't directly manipulating them.

Among other things, the VB6 program had a timer that woke up every 4 seconds, manipulated some global variables and went back to sleep, while the main program was doing its thing. I can't understand why this didn't result in collisions.

The "timer" is on a separate thread created for the timer, but when it calls into your code, you are guaranteed not to interrupt any other functions, because the function calls are basically queued one at a time in the thread.



回答2:

My question is Do VB6 event handlers run in separate threads?

Common answer: No.

Real answer: Yes, if you make nasty Win32 calls to spawn more threads. The odds of doing this correctly are close to zero. I don't think I've ever seen it in real code.

Among other things, the VB6 program had a timer that woke up every 4 seconds, manipulated some global variables and went back to sleep, while the main program was doing its thing. I can't understand why this didn't result in collisions.

When the timer wakes up, it puts a message in the UI's queue. When the UI goes idle, it processes the message and runs the event on the UI thread.

You can do the same thing in WinForms if you use the right timer.



回答3:

To Matt Wilko, DoEvents is VB6 implementing a virtual cooperative multithreading thing. What's a thread, something that can be interupted to run other code. When you use DoEvents you interupt the execution of your code, when the CPU does multithreading it preempts your code. The effect is the same. One done by VB6 runtime and one by the CPU.

The effect is the same. YOU NEED TO SYNCHRONISE ACCESS TO GLOBAL OBJECTS and VARIABLES.

Your event Handlers aren't supposed to run too long. Each event is queued and run one at a time.

Also the way to multithread a VB6 thing is to put other things in a COM Exe file with a asynchronous model. The exe calls back when finished.