Creating Multi-Threaded VB5/SP2 Apps

Daniel Appleman

Have you noticed that Dan has avoided discussing multi-threading in VB5? The reason is simple: He didn't think it was particularly safe to create multi-threaded applications with the original version of VB5. But now that Service Pack 2 is available, it's a different story.

Several people have recently asked me how to create multiple threads in VB5 applications. Some have mentioned the CreateThread API and wondered why I didn't discuss it in my Win32 API book. Well, I'll have a few things to say about the CreateThread API later. You see, I believe it's my responsibility to address not only what you can do with VB, but what you should do as well-and the CreateThread API opens a nest of problems that programmers should face with trepidation, if not outright terror. For the past couple of months I've been answering VB threading inquiries with a cryptic "just wait." I was using the beta version of the new VB Service Pack 2 (SP2), so I knew what was coming. This update to VB5 allows you to create multi-threaded VB5 applications safely.

Now, if you aren't familiar with multi-threading, this column isn't going to make much sense to you. One good source of information is Chapter 14 of my book Developing ActiveX Components with Visual Basic 5.0: A Guide to the Perplexed. This article assumes that you're familiar with multi-threading as it was implemented in VB5.

What a difference a few dialog controls make

In the original VB5, the multi-threading capabilities of an ActiveX server were set in the Project Properties (General) dialog box. This dialog box included a check box titled "Unattended Execution" and two option buttons: one marked "Thread per object," the other "Thread Pool," with the number of threads specified in a text box.

The "Unattended Execution" check box first prevented the server from using any user interface elements such as forms or message boxes. This was the first requirement for multi-threading with VB, because the VB forms engine was not thread-safe. VB uses the so-called "apartment model" of multi-threading, in which all of your components' global variables are thread-specific. In other words, VB makes a separate copy of all of your global variables for each thread. This eliminates most shared memory and synchronization problems, making apartment-model multi-threading relatively safe and easy to use. But because VB5 could not isolate form level variables among threads, it required that multi-threading servers have no user interface elements.

With VB5 SP2, Microsoft figured out how to isolate forms between threads, extending the forms engine to run in the apartment model as well. The "Unattended Execution" check box is still there, but now it's completely independent of the server's multi-threading capabilities.

The multi-threading options are selected in two ways:

I expect the first of these options to be more common. You shouldn't use a form in a separate thread unless your application's design provides a compelling reason to do so.

Now show me an example!

The ThreadTest1 example is a very simple multi-threaded client. The main window has a button that allows you to display the background forms in their own threads using the following code:

Private Sub frmForeground_Click()
   Dim s As clsBackground
   Set s = CreateObject("ThreadTest1.clsBackground")
End Sub

Each background form has a button that starts a very long loop operation, as follows:

Private Sub Command1_Click()
   Dim l&
   For l = 1 To 10000
      Label2.Caption = Str$(l)
      Label2.Refresh
   Next l
End Sub

Each form also has a label control on which it displays its current thread identifier. Try running the program first in VB (be sure the project startup setting is StandAlone). You'll see that each form runs in the same thread, and that a long operation on one form blocks the operation of all the others. The forms and objects exist in a single thread because the VB environment itself doesn't support multi-threading.

Now compile it to an executable and try running the executable. You'll see that each form runs in its own thread, and that a long operation on one form doesn't interfere with the others.

What about the CreateThread API?

You've seen how VB5 can now be used to create true multi-threaded applications. But if you've been reading other industry publications, you might be wondering why I haven't discussed the use of the CreateThread API with VB. Well, I've seen those articles, and I've done quite a bit of work with the CreateThread API-and I have a lot to say about the subject. You see, the CreateThread API can be used effectively from VB-but only with great care and only by observing certain precautions that seem to have been forgotten in many of the discussions on the subject.

You can find out more on this topic, because this month's column also includes a two-for-one special. A feature article that I've written about using the CreateThread API from VB called "A Thread to Visual Basic" can be found at http://www.desaware.com/thread.htm. You'll need to enter the code VBDV10 to view the article (the article is free-we're doing this as a form of market research). I think you'll find it quite interesting. s

Download DAN1197.ZIP at www.pinpub.com/vbd

Daniel Appleman, author of the Visual Basic Programmer's Guide to the Windows API, the Visual Basic Programmer's Guide to the Win32 API, How Computer Programming Works, and Developing ActiveX Components with Visual Basic 5.0: A Guide to the Perplexed, has been developing applications for Microsoft Windows since its release in 1985. In 1991 he founded Desaware Inc., a Campbell, CA-based software company focusing on component-based software and advanced tools for developers. dan@desaware.com, 70303.2252@compuserve.com.