Thursday, June 18, 2015, 3:57:22 PM
A few days ago somebody asked a question on the Universal Thread on whether it’s possible to run a Visual FoxPro COM component as a free threaded component. Questions like this come up frequently, because there is a general sense of confusion on how Visual FoxPro’s multi-threading actually works, so lets break this down in very simple terms.
Visual FoxPro is not Multi-threaded
The first thing to understand is that Visual FoxPro is not actually multi-threaded in the sense that say a native C++ component is multi-threaded.
Visual FoxPro is based on a very old and mostly single threaded code base. Your FoxPro code that runs as part of your application always runs on a single thread. This is true whether you are running a standalone EXE, inside of the VFP IDE or inside of an MTDLL. Behind the scenes there are a few things that Visual FoxPro does that are truly multi-threaded, but even those operations converge back onto a single thread before they return to your user executed code in your application. For example, some queries and query optimization that use Rushmore are executed on multiple threads as do some ActiveX interactions that involve events. The FoxPro IDE also does a few things interactively in the background. You can also call from FoxPro into a native DLL or a .NET Component and start new threads outside of the actual Visual FoxPro runtime environment. But when we’re talking about the actual code executing in your mainline programs – they are single threaded. 1 instance of your executing FoxPro code == 1 thread essentially.
Keep this in mind – Visual FoxPro code is single threaded and it can’t and won’t natively branch off to new threads. Further FoxPro code assumes pretty much it’s the only thing running on the machine so it’s not a particularly good citizen when it comes to giving up processor cycles for other things running on the same machine. This means Visual FoxPro will often hog the CPU compared to other more multithread aware applications do. Essentially VFP will only yield when the OS forces it to yield.
Visual FoxPro supports running inside of some multi-threaded applications by way of a mechanism called STA – Single Threaded Apartment threading. VFP9T is not thread safe internally. It is thread safe only when running in STA mode called from a multi-threaded COM client that supports STA threading.
So what is a Multi-Threaded VFP COM DLL?
If you create VFP component with BUILD DLL MTDLL you are creating an STA DLL. STA stands for Single Threaded Apartment and it stands for a special COM threading model that essentially isolates the DLL in it’s own separate operating container. STA components are meant for components that essentially are otherwise not thread-safe. A thread safe component is a component that can use a single instance to get instantiated from multiple threads and run without corrupting memory. Essentially this means that a free threaded component needs to be able to have no shared state or if it does have shared state that shared state has to be isolated and blocked behind sequential access (Critical Sections or Mutexes etc.) to essentially serialize the access to any shared state.
Visual FoxPro DLL – MTDLL or otherwise - do not qualify as thread safe. FoxPro has tons of shared state internally and if that shared state were to be accessed simultaneously from multiple threads – BOOOM! So FoxPro is not a true multi-threaded component.
This answers the original question: Visual FoxPro cannot run as a Free Threaded component directly as a DLL.
However, there are several ways that you can run VFP COM components in free threaded mode but not directly as a DLL. I’ll talk about that a bit later on.
STA For Multi-Threading
Ok so Free Threading is out for a DLL. But you can build MTDLL components which are STA components that can be used in multi-threaded environments that support STA components. For example, you can use ASP or ASP.NET pages to call FoxPro COM components and these components will effectively be able to run multiple simultaneous requests side by side.
This works by way of COM’s Apartment Threading model which essentially creates isolated apartments and caches fully self contained instances of the COM DLL in a separate storage space – the apartment. What this means is that when you create a new VFP COM component COM creates a new COM apartment and loads your DLL and the VFP runtime DLLs into it. COM leaves that apartment up and running. When the next request comes in it activates the same apartment with the already running runtimes inside of it, reattaches the component and thread state and then executes the request in the same apartment. If multiple requests come in simultaneously while all other apartments are busy a new one is created, so effectively you end up with multiple copies of the Visual FoxPro runtime running simultaneously, side by side. As requests come in they are routed to each of these existing apartments and the COM scheduler decides how long the apartments persist.
All of this happens as part of the COM runtime with some logic as part of the STA component in the VFP runtime that makes it possible to launch your VFP COM component and link the VFP runtime which is doing the heavy lifting. Behind the scenes each apartment then has its own thread local storage address space, which can hold what otherwise would be global shared data. A FoxPro MTDLL essentially maps your VFP component to a separate VFP9T runtime that stores all of its shared stated in thread local storage, rather than on the global shared memory. This is why there are a few things that don’t properly work in MTDLL components – the memory usage is different and in fact a bit less inefficient as all shared state and buffers are stored in TLS.
What all this means is that in STA mode when simultaneous requests come in and process at the same time, the VFP runtime effectively runs multiple instances of the runtime side by side and thus ensures that there’s no memory corruption between what would otherwise be shared data.
If you want to understand how this works, try setting up a COM component that runs a lengthy query. Then first create a DLL Component (not MTDLL) then load this into an ASP or ASP.NET application and hit the page with multiple browsers (or a tool like West Wind Web Surge for load testing). After a few hits you’ll like see errors popping up in IIS finding that your COM component crashed. This is due to the memory corruption that occurs when your are not using the STA optimized DLL compilation.
Then recompile in MTDLL mode and try the same exercise again – you’ll find that now you don’t get a crash because the shared state is protected by multiple instances of VFP9T.DLL. If you want to look at this even deeper fire up Process Explorer and open the host process (w3wp.exe for the IIS Application Pool), then drill into the properties and loaded DLL dependencies. You’ll see multiple instances of your DLL and the VFP9T.dll and your application DLL loaded (assuming you’ve loaded the app hard enough to require multiple instances to run simultaneously).
There's no reason not to use MTDLL COM components using STA if you can. STA is effective in isolating instances and that's as efficient as you are going to get. For do nothing requests it's possible to easily get around 2000+ req/sec on mid-range quad core i7 system. However, things get A LOT slower quickly as soon as you add data access and returning object data to the COM client, so the actual raw throughput you can achieve with STA is far outweighed by the CPU overhead of doing anything actual useful inside of your FoxPro code. Running a query and returning a collection of objects of about 80 records for example drops the results down to about 8 req/sec. Call overhead is a nearly useless statistic when it comes to VFP COM objects, so even if free threading were possible and even if it were 10x faster than STA threading, it would have next no effect at all on throughput for most requests that take more than a few milliseconds. STA is the most effective way to get safe and efficient performance.
Where STA and MTDLLs fall short is error recovery. If an STA component fails with a C5 error or anything that hangs a component, the component will remain loaded but won’t respond to further requests. The COM STA scheduler still thinks that component is active and running which results in potentially confusing intermittent errors where say every 3rd request results in an error. There’s no good way to recover from that, short of shutting down the host process (IIS application pool). There’s no way to shut down COM DLLs for maintenance tasks either – short of shutting down the Host process. So if you need to run tasks like reindexing or packing of your data you need to really think ahead about how to do this as you have to kill all instances and then ensure only a single instance (ie. 1 not overeager user) is doing the administration tasks in order not to trigger multiple instances that have files open.
Bottom Line: STA components provide a good simulation of multi-threading and this is the best way for getting multi-threaded components into a multi-threaded host like IIS typically – assuming the host supports STA threading and provided you don’t have very frequent admin tasks that require exclusive access you need to run against the server.
STA Support – not always available
STA is a good option for multi-threaded FoxPro code, but it’s not always available. In fact, more and more STA support is going away because the era of legacy COM components like FoxPro and VB6 has pretty much disappeared for high level development and is relegated now to system components which typically can support free threading. For example, the only ASP.NET technology that officially supports STA components is ASP.NET WebForms. ASP.NET MVC, ASMX Web Services, WCF, Web API and vNext all don’t have native support for STA built in.
There are ways to hack around this and I have a blog post that covers how to get STA components into various technologies:
which lets you use FoxPro components in different .NET technologies.
Free Threading – You Can Do It, but…
Earlier I said that it’s not possible to use VFP DLL COM components directly to run in Free Threaded environments. However, there are a couple of options available if you step outside of the box and use some component technology:
- Use a COM+ Component
- Use an EXE Server
Both of these technologies essentially create fully self contained objects. COM+ provides a host wrapper that can run either in process or out of process, while an EXE server is on its own a fully self contained instance. Both technologies have one big drawback: They are slow to create and dispose of instances.
COM+ is a wrapper technology that you can access on Windows using the Component Services plugin (make sure you run the 32 bit version of it for Fox components). COM+ allows you to register a VFP MTDLL COM component which essentially creates a registry redirect to instantiate your COM component through the COM+ runtime. The COM+ runtime creates a host container that essentially provides the STA Apartment that VFP expects and every access of the COM component is then routed through this HOST container. The actual ClassID points at COM+ with special keys that actually point at the ClassID for your component. The container loads itself then loads and executes the actual COM component inside of it.
COM+ supports both In Process and Out of Process activation modes but even the in-process mode tends to be fairly slow adding a lot of overhead for each call made to the container.
COM+ is also a bit of a pain to work with for debugging and updating of components. In order to update a COM component you have to unload the COM+ container and if the interface of the COM object changes you have to reregister the component in the COM+ manager which is fairly painful during development.
You can also use an EXE server to run as a Free Threaded component. Because an EXE server is effectively an out of process component there’s no overlap in shared memory or buffers and so launching an EXE server is an option for executing in a free threaded environment. The limitation with this is that the calling server has to support IDispatch invokation of COM objects.
Like COM+ loading up an EXE component is slow because each time it’s instantiated a new instance of the VFP runtime is required. While the runtime disk images cache it’s still pretty slow to load up and shutdown full processes. However, if performance is not critical and you have to support free-threaded environments this is one of the easiest ways to make it work!
There other alternatives in how to run EXE servers – like running a pool manager of instances so that instances are loaded and then cached rather than having to be restarted each time. I use this approach in West Wind Web Connection, and by removing the overhead of loading a VFP instance each time and keeping VFP’s running state active, raw request throughput performance actually rivals that of DLL server with this approach. However, this sort of thing only works if you can control actual activation as part of the application you are building (as I do in Web Connection).
Multi-threading in FoxPro is a tenous thing. It’s possible due to some very creative hackery that was done on the VFP runtime to effectively make a single threaded application run in a multi-threaded environment. STA threading is a reasonable solution to make FoxPro work in those environments that support it. Unfortunately STA support is getting less and less implemented by new technologies so it’s harder to find places where STA components will actually work anymore. When STA doesn’t work there are alternatives: Using COM+ or if performance doesn’t matter much EXE servers can be used as well and both of these technologies work in fully free threaded environments at the cost of some performance.
Today if you’re starting with any sort of new project, the recommendation for multi-threaded applications is to look elsewhere than FoxPro. Most other environments have native support for multi-threading so it’s much easier to integrate into multi-threaded environments.