COM interface: Using STA instead of MTA - multithreading

I am working with a COM interface that, according to ThreadingModel = "Free" in it's CLSID entry in the registry, supports multithreaded apartments. Multithreading seems to be implemented at a very basic level, however, very often method calls return a "Class is busy" status code.
Is there any risk of switching to STAs in CoInitializeEx and using interface marshaling to have the COM system serialize the requests and to avoid this behaviour (which I never experienced when only making calls from the main thread)?
Thanks!

Using an STA thread to host the COM object will not make any difference. COM pays attention to the ThreadingModel value in the registry. Since it is "Free", it will not see any need to marshal the interface pointer and will still makes the call from the worker thread.
You would have to monkey with the registry key and change it to "Both".
This is not a great solution, it will break at a drop of a hat. It is just far better to take care of this yourself. Use Control.Begin/Invoke() or Dispatcher.Begin/Invoke(), depending on which class library you use to implement the required message loop. Note that you now also have a choice, the COM marshaling is equivalent to Invoke() but you can (possibly) optimize by using BeginInvoke().
And last but not least, duplicating the locking that exists in the COM server that produces the "busy" error code is a possible solution. Non-zero odds that you'll solve this by acquiring your own lock before you make each call, thus serializing the calls yourself. Your worker thread will now block instead of having to deal with the error code. Contacting the author of the component would be wise, he can easily tell you which specific methods you should serialize.

Related

Should VCL Components Use Thread-Safe Functions

I am working on a custom VCL-only date edit component. Am planning on using the System.SysUtils.FormatDateTime function to convert a TDate to a string. There are two versions of FormatDateTime--one is thread-safe and the other is not. Since the VCL is not thread-safe, should I prefer the thread-safe version or is the non thread-safe version okay to use?
tl;dr use threadsafe version
If you use the non threadsafe version then you constrain any consumer of your component not to use that same non threadsafe version in a thread.
That's not an unreasonable constraint by any measure. Using the non threadsafe version is only really viable in a program that never does so away from the main thread. So a program would have to be breaking the rules in the first place for your component to be caught up in the fallout.
Having said that, a component author should as a principle avoid making any assumptions about the consuming program. So best practice is to call the threadsafe version. Then there can be no debate. Your program cannot be involved in any thread safety issue with these locale global variables.
So long the caller will be the main thread, it doesn't matter if you choose a non thread safe variant of the function. Which in this case seems to be (if you are not creating inside of your component a worker thread from which you were calling that function, and you adhere to the rule that you won't use your control inside any worker thread, you'll be safe with it).
But there's more to consider. If you have recent Delphi version and keep UpdateFormatSettings property enabled, a globally declared format settings variable used in non thread safe overload of the FormatDateTime function will get updated when the user modifies their local settings on their system. I can't say anything about a control notification (so you could update the output) because I'm having only D2009 by hand right now and these changes has been added later.

Which implementations of Condition do not require current thread to hold the lock?

Recently I read some examples from the Chapter 8 of the The Art of Multiprocessor Programming, about “Monitors and Blocking Synchronization” that use the signalAll() of a Condition object, without the acquisition of the lock associated with that Condition.
Surprisingly I did not find any fix for those examples in the book’s errata. Moreover they propose a correction for the example of figure 8.12 of a FifoReadWriteLock, but they keep using the signalAll() without the lock held. That perturbed me and I tried to find other considerations about these examples to understand the reasons why these Java examples were written in this way.
For instance, the answer to the question “How does a read-write mutex/lock work?” shows the same example of the implementation of a FifoReadWriteLock, which implements the writeUnlock() as:
void writeUnlock() {
writer = false;
condition.signalAll();
}
About the absence of the lock acquisition you can read two different reasons:
only use it as pseudo code
some implementation of a condition variable doesn't require that the lock be held to signal.
It is difficult to accept the first argument since the book use examples in Java and explicitly says:
The book uses the Java programming language.
About the second point, I know that the Java API in java.util.concurrent.locks.Condition states for signal() method:
An implementation may (and typically does) require that the current thread hold the lock associated with this Condition when this method is called.
If "an implementation may" only, that means that it is NOT mandatory. Yet, to the best of my knowledge I don’t find any implementation that does NOT fulfill this requirement. So I would like to know which implementations of Java Condition do not require current thread to hold the lock?
I'm not aware of any Condition implementation in the JDK that allows waiting or signaling without owning the monitor at the same time.
Practically all of the java.util.concurrent classes rely on AbstractQueuedSynchronizer which establishes the same contract as the built-in monitor methods wait()/notify()/notifyAll() for the condition variables it provides, i.e. it requires owning the internal lock in order to allow calling await()/signal()/signalAll().
If you try a simple example using the proposed FifoReadWriteLock, you'll find that it spews a serious amount of IllegalMonitorStateExceptions courtesy of its writeUnlock() method. These exceptions disappear if you apply the lock-try-finally approach from the other methods.
While indeed owning the monitor is not absolutely required to wait or signal, often it's the preferable approach, as it saves you from racy condition reads, it shouldn't be too costly as the hand-off between the internal wait sets of the same monitor can still be done fairly efficiently, and because most often you need it for both signaling and scheduling instead of just signaling.

OpenFileDialoug Current Thread Must Be STA before OLE calls made

Can someone explain to me what this error I'm seeing is?
Current thread must be set to single thread apartment (STA) mode before OLE calls can be made.
Specifically, I'm trying to open the SaveFileDialog/OpenFileDialog within C++/CLI on a form.
SaveFileDialog^ saveFileDialog1 = gcnew SaveFileDialog;
saveFileDialog1->ShowDialog();
if (saveFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)
{
s = saveFileDialog1->OpenFile();
}
s->Close();
}
The error that is throwing is
An unhandled exception of type 'System.Threading.ThreadStateException' occurred in System.Windows.Forms.dll
Additional information: Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it. This exception is only raised if a debugger is attached to the process.
I'm not really familiar with what this error is saying. I know just a bit about threading, but I'm not sure how threading would be an issue here. I've seen some people reference things like STAThread without providing a clear explanation as to what it does, and Microsoft's documentation makes no mention of having this exception thrown when calling SaveFileDialog/OpenFileDialog, or how to handle it.
Thanks!
When you use OpenFileDialog then a lot of code gets loaded into your process. Not just the operating system component that implements the dialog but also shell extensions. Plugins that programmers write to add functionality to Windows Explorer. They work in that dialog as well. There are many, one you are surely familiar with is the extension that makes a .zip file look like a folder.
One thing Microsoft did when they designed the plug-in interface is to not force an extension to be thread-safe. Because that is very hard to do and often a major source of bugs. They made the promise that the thread that creates the plugin instance is also the thread on which any call to the plugin is made. Thus ensuring that the plugin is always used in a thread-safe manner.
That however requires a little help from you. You have to make a promise that your thread, the one that calls OpenFileDialog::Show(), observes the requirements of a single-threaded apartment. STA for short. You make the promise with the [STAThread] attribute on your program's Main() entrypoint. Or if it is a thread that you created yourself then by calling Thread::SetApartmentState() before you start it.
That's just a promise however, you also have to implement what you promised. Takes two things, you promise to never block the thread and you promise to pump a message loop. Application::Run() in a .NET program. The never-block promise ensures that you won't cause deadlock. And the message loop promise says that you implement a solution to the producer-consumer problem.
This should never be a problem, it is very unclear how this got fumbled in your project. Another implicit requirement for a dialog is that it must have an owner. Another window on which it can be on top of. If it doesn't have one then there are very high odds that the user never sees the dialog. Covered by another program's window, the user can only ever find it back by accident. When you create windows then you always also must call Application::Run() so the windows can respond to user input. Use the boilerplate code in a C++/CLI app so this is done correctly.

What can I hook to confirm I don't touch the VCL from outside the main thread?

I'm new to threaded programming. (in XE7)
I'm nervous that I may have inadvertently called procedures that access the VCL from a thread. My understanding is that this is dangerous.
I've added the code below to some of my procedures that touch the VCL.
(*$IFDEF DEBUG *)
Assert((Windows.GetCurrentThreadId = System.MainThreadID), "Thread error");
(*$ENDIF *)
Hopefully, this will catch any calls I made to my VCL-accessing procedures while in a thread.
It occurred to me that if I could insert this code into some VCL low-level code, that it would be more effective at catching illegal VCL access from a thread.
I have never dug into the VCL code, so I'm asking for feedback. Is there some central place in the VCL code that would be a good place for this code?
TComponent.Create is a nice low level place, but I'm not concerned with controls being created. I'm more concerned with accessing properties (.Left, .Checked) etc.
TIA
This cannot be done.
One thing that goes a little bit in that direction is the TVirtualMethodInterceptor in System.Rtti. You could use that to hook all virtual methods of some common classes like TControl or TCheckbox. Things like SetChecked or SetBounds are implemented as virtual methods. So you might be able to hook these. But you'd still have to proxify every instance of these classes.
Look at the Delphi help for an example.

Does the inability of IMessageFilter to handle 0x800AC472 (VBA_E_IGNORE) make implementing IMessageFilter irrelevant?

From msdn it seems that IMessageFilter doesn't handle all exceptions, for example, at some points, office applications 'suspend' their object model, at which point it cannot be invoked and throws: 0x800AC472 (VBA_E_IGNORE)
In order to get around this, you have to put your call in a loop and wait for it to succeed:
while(true)
{
try
{
office_app.DoSomething();
break;
}
catch(COMException ce)
{
LOG(ce.Message);
}
}
My question is: if this boiler-plate code is necessary for each call to the office app's object model, is there any point in implementing IMessageFilter?
Yes, the two mechanisms are independent. IMessageFilter is a general COM mechanism to deal with COM servers that have gone catatonic and won't handle a call for 60 seconds. The VBE_E_IGNORE error is highly specific to Excel and happens when it gets in a state where the property browser is temporarily disabled. Think of it as a modal state, intentionally turned on when Excel needs to perform a critical operation that must complete before it can handle out-of-process calls again. A lock if you will. It is not associated with time, like IMessageFilter, but purely by execution state. Geoff Darst of the VSTO team gives some background info in this MSDN forums thread.
Having to write these kind of retry loops is horrible of course. Given that it is an execution state issue and assuming that you are doing interop with Excel without the user also operating the program, there ought to be a way to sail around the problem. If you are pummeling Excel from a worker thread in your program then do consider reviewing the interaction between threads in your code to make sure you don't create a case where the threads are issuing Excel calls at roughly the same time.

Resources