That doesn’t look so bad now, does it? Of course there’s a lot more to multithreading. The first step in enhancing my sample would be to get rid of that fRunning global variable and use a real synchronization technique such as semaphores, events, mutexes, or critical sections. You might also want to send data between threads using handle sharing, pipes, mailslots, or other communication techniques or define some data for your thread using the Thread Local Storage (TLS) API functions. At some point, you would probably want to encapsulate common thread behavior in public classes, although the actual thread procedures must remain in standard modules. In fact, someone with more thread experience than me could probably write a book as long as this one called Hardcore Visual Basic Threads.
The first question a person determined to become a Visual Basic thread expert would have to ask is this: What can you safely do in a Visual Basic thread? In other words, what parts of the language are thread-safe? Thread-safe means that the code has been written so that it can be safely reentered at any time by any thread. When multiple threads are running, the operating system automatically switches between them. One thread might be in the middle of the Hobgoblin function when it loses control. Another independent thread gets control and calls the Hobgoblin function. But the first thread has modified a global variable used by Hobgoblin. The second thread comes in and modifies the same variable. The first thread gets control back, but the variable it was depending on to have the same value it had just a few microseconds ago has been mysteriously modified. If the modified variable contained a pointer to something (such as a string), you’ll probably crash. If it contained numeric data, you might be lucky enough to get random results.
Thread-safe libraries must be written very carefully to ensure that each thread has independent data or, if data is shared, that different threads cooperate in accessing it. Part of the Visual Basic library has been rewritten to be thread-safe. If this weren’t true, the automatic threading in ActiveX EXE components marked for unattended execution wouldn’t work. But you’re on your own figuring out exactly which parts. You’re usually safe using any Visual Basic procedure that has no connection with a user interface, but anything related to forms, controls, or message boxes is suspect. You can guess, but the only way to know for sure is to try it. The official Visual Basic position is that multithreading isn’t supported, and if you go whining to the support people about crashes in your thread procedures, you’ll probably hear muffled laughter on the other end of the phone.
That leaves you in a tough position. If something goes wrong (and it will), you don’t know whether to blame the Visual Basic library or your code. There are definitely some parts of the Visual Basic language that are not thread-safe, but nobody’s going to tell you what those parts are. On the other hand, coding for multiple threads is such a different way of thinking for most Visual Basic programmers that you also have to suspect your own code. And debugging code for multiple threads ranges from difficult to impossible in the Visual Basic IDE. It’s actually easier to debug by compiling to native code and debugging in
the thread-aware Visual C++ environment rather than in the Visual Basic environment.
All these problems remind me of a Mark Twain story that lampooned a certain type of ridiculous adventure story common in his day. After taking his heroes through a series of increasingly harrowing situations, he ended the story with the comment that he had created an impossible predicament and had no idea how to resolve it. That’s where I’m going to leave you with the multithreading adventure. Have fun and good luck.
In the long run, I think Visual Basic multithreading will only be safe and reliable when it is added to the language. Not only will the library have to be modified to be completely thread-safe, but statements and attributes will have to be added so that you could specify that a procedure is a thread. High level features would also be needed to make the most common types of synchronization easy. And, of course, the debugger must be enhanced to handle threads. Maybe we’ll see that in the next version. (That’s what I said last time.)