views:

104

answers:

1

I have written a com component in .NET and if I try to take a lock on any object in any method (that is invoked by unmanaged code talking to my com component) I get an exception.

I do not have the exact text of the exception at this moment but it wasn't much helpful either.

So my question is under what circumstances a lock(syncObject) would throw an exception? Here are some facts:

  • syncObject is not null
  • syncObject is not already locked

Would it have anything to do with callee running in STA (Single Threaded Apartment) or MTA (Multi Threaded Apartment)?

+1  A: 

From this page:

Every lock acquisition might throw an exception. Be prepared for it.

Most locks lazily allocate an event if a lock acquisition encounters contention, including CLR monitors. This allocation can fail during low resource conditions, causing OOMs originating from the entrance to the lock. (Note that a typical non-blocking spin lock cannot fail with OOM, which allows it to be used in some resource constrained scenarios such as inside a CER.) Similarly, a host like SQL Server can perform deadlock detection and even break those deadlocks by generating exceptions that originate from the Enter statement, manifesting as a System.Runtime.InteropServices.COMException.

Often there isn’t much that can be done in response to such an exception. But reliability- and security-sensitive code that must deal with failure robustly should consider this case. We would have liked it to be the case that host deadlocks can be responded to intelligently, but most library code can’t intelligently unwind to a safe point on the stack so that it can back-off and retry the operation. There is simply too much cross-library intermixing on a typical stack. This is why timeout-based Monitor acquisitions with TryEnter are typically a bad idea for deadlock prevention.

So as you can read, it seems that under resource constrained conditions we might get exceptions thrown from the Enter method of Monitor which lock(o) uses internally.

So perhaps your solution is something like a spin-wait?

{
    uint iters = 0;
    while (!cond) {
        if ((++iters % 50) == 0) {
            // Every so often we sleep with a 1ms timeout (see #30 for justification).
            Thread.Sleep(1);
        } else if (Environment.ProcessorCount == 1) {
            // On a single-CPU machine we yield the thread.
            Thread.Sleep(0);
        } else {
            // Issue YIELD instructions to let the other hardware thread move.
            Thread.SpinWait(25);
        }
    }
}

Where cond could be some

private volatile int cond = 0

used with e.g. Interlocked.CompareExchange where you change to e.g. Thread.Current.ManagedThreadID or something else non-zero?

Henrik
Lack of resources may not be the problem in my case but you've answered the question anyway so I've accepted it.My wild guess is that COM callee is in a state of transaction where locks are irrelevant therefore it throws an exception.
Hasan Khan