views:

44

answers:

1

It seems that these code snippets ought to behave identically:

1: Monitor.TryEnter(object)

if (Monitor.TryEnter(lockObject))
{
    try
    {
        DoSomething();
    }
    finally
    {
        Monitor.Exit(lockObject);
    }
}

2: Monitor.TryEnter(object, ref bool) - introduced in .NET 4.0

bool lockAcquired;
try
{
    Monitor.TryEnter(lockObject, ref lockAcquired);
    if (lockAcquired)
    {
        DoSomething();
    }
}
finally
{
    if (lockAcquired)
    {
        Monitor.Exit(lockObject);
    }
}

I see from the MSDN documentation on the overload taking a ref bool parameter:

If the lock was not taken because an exception was thrown, the variable specified for the lockTaken parameter is false after this method ends. This allows the program to determine, in all cases, whether it is necessary to release the lock.

But the documentation also states that the overload taking only the object parameter throws no exceptions other than ArgumentNullException. So it seems like if an exception were thrown in code snippet 1 above, it could only be because lockObject is null, in which case no lock was taken (and TryEnter would've returned false) anyway, so the Monitor.Exit call would not be needed.

Clearly they would not have introduced this overload for no reason. So what scenario is the Monitor.TryEnter(object, ref bool) method intended to address?

+4  A: 
  1. Monitor.TryEnter could succeed and then an asynchroneous exception like ThreadAbortException or OutOfMemoryException (that can happen without visible allocations) is triggered. Then the lock would be taken but never released.

See: Locks and exceptions do not mix

usr
Wouldn't this be true of either overload, though? That is, how would this scenario be prevented by the second overload?
Dan Tao
Ohhh I see (visited the link)... so in other words an exception could be thrown after the `TryEnter` but before entering the `try`/`finally` block. Got it.
Dan Tao
Too bad there's no "nice" way to apply similar logic to a "Using"-style block. It's possible to kludge a constructor to 'sneak out' a reference to a partially-constructed object before it does anything that will need to be undone, and only invoke the constructor from a factory method which can use the smuggled reference to dispose the partially-constructed object, but it would be nice if there were a better way to do that. Maybe change the framework so that if construction fails on an object which implements iDisposeOnConstructorException, the framework would call iDOCE.dispose on it?
supercat
The current JIT contains a hack that makes the 'sneak out' scenario impossible. You can also reimplement the using-block yourself: C c = null; try { c = new C(); } finally { if (c!= null) c.Dispose(); }
usr