What important difference exists between Monitor.T

2019-03-13 08:43发布

问题:

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?

回答1:

  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