Sunday, May 17, 2009

Thread-Threat

At work, I'm trying to get a software-feature faster by introducing multithreading. We import data from a device and convert it into our format. This is done sequentially at the moment, first importing, then converting. First tests have shown that we can get a benefit of about 30% if we do that in parallel. So I developed a wonderful producer-consumer-queue with a producer-thread and a consumer-thread which gets its data from the producer-thread. So far, so good: all unit-tests with that queue ran successfully.

However, as soon as I plugged that code into the import-conversion-piece to make it multithreaded, I got System.Runtime.InteropServices.COMExceptions with HRESULTs of -2147467259 (RPC_E_SERVERCALL_RETRYLATER, Unspecified error) or -2147417856 (RPC_E_SYS_CALL_FAILED, System call failed) - (here is a list with automation errors). These errors occured randomly on different parts of the code. But all code-parts had in common that they're calling a VB6-COM-object (well, it's a COMException - what should I expect...).

Some googling brought me similarities with Office-automation (see here and here for example). My picture about that problem became clearer and clearer and I sketched that diagram to understand it:


Thread A and B are accessing the same COM-object. This access is provided via a RCW (runtime callable wrapper). There is only one RCW for all accesses to that COM-object (read the great article series "Beyond (COM) Add Reference: Has Anyone Seen the Bridge?" of Sam Gentile for a deeper dive into COM-interop). This means multithreading and COM-interop is no fun.

What about protecting the access to that COM-interop with a lock? I designed a little construct so that I won't forget to protect any calls to that COM-interop:


The wrapper for the COM-interop, ThreadSafeComInterop, offers the COM-interop via a Lock-class. Each time you want to access the COM-object, you acquire the lock. With that, a Monitor enters the lock and exits it not until the lock is disposed. It's neat with the using-construct:

Using lock = _interop.Lock
' do something with lock.ComInterop
End Using

See that sequence-diagram for further information:


The provider creates the ThreadSafeComInterop by passing the COM-interop to the constructor. The recipient can call the Lock via the using-construct and access the COM-interop via lock.ComInterop. By creating the ThreadSafeComInteropLock, a Monitor.Enter is established on a static lock-object. When finished using the COM-object, the Lock is being disposed and Monitor.Exit is being called to allow other components to access the COM-object.

This sounds great and tests are showing that the exception-rate is degreasing from 10 tries - 9 exceptions to 10 tries - 1 exception. But unfortunately, this exception is one exception too much. Reading "Lessons Learned Automating Excel from .NET" finally convinced me to write the needed parts of the COM-component in .NET.

Friday, May 1, 2009

BendingStackPanel

I just finished a nice little tool for our Message-module: Message.dll for dummies.

On the right is a ListView with various components of which the trace-level can be altered. In the center of the dialog are 3 Buttons to vary the debug-mode. These buttons are on a StackPanel with a custom-made property "Bend" and overrides to Measure and Arrange. You can bend the StackPanel up to 180 degrees. Here is a picture with more buttons and an ellipse (any UIElement can be added):

The slider and the TextBlock binds to the BendingStackPanels Bend-property so that you can interactively bend and unbend the panel - looks really cool :) I was amazed how straightforward the development was: it took me just a few hours! Here is the envelope of ideas - nice, eh? ;)

The whole bending-stuff is just class-10 (yes, I looked it up...) sine- and cosine-trigonometry. You can have a look at the code here.