Question on using Monitor.TryEnter and locking object

Viewed 16743

Consider the following function that implements non-blocking access to only the one thread.

public bool TryCancelGroup()
{
    if (Monitor.TryEnter(_locked))
    {
        if (_locked == false)
        {
            _locked = true;

            try
            {
                // do something
            }
            catch (Exception ex)
            {
                _locked = false;
            }
            finally
            {
                Monitor.Exit(_locked);
            }
        }
        return _locked;
    }
    else
    {
        return false;
    }
}

And here is how _locked variable is defined.

bool _locked = false;

Now when program reaches Monitor.Exit(_locked); it throws an System.Threading.SynchronizationLockException saying that _locked variable was not synchronized before.

It all was working before when _locked variable was defined as object

object _locked = new object();

When I changed it to bool in order to use it as boolean flag I started getting this exception.

3 Answers

To add to the success above - to be sure the lock is released - the TryEnter() and Exit() can be wrapped in a custom class as an extension to object taking a Delegate and Timeout as a parameter.

public static class MyMonitor
{

    public static bool TryEnter(this object obj, Action action, int millisecondsTimeout)
    {
            if (Monitor.TryEnter(obj, millisecondsTimeout))
            {
                try
                {
                    action();
                }
                finally
                {
                    Monitor.Exit(obj);
                }
                return true;
            }
            else
            {
                return false;
            }
    }
}

And called like this waiting 1000 ms to obtain the lock or throw an error if timeout:

if (!_locked.TryEnter(() =>
{
    //Exclusive access code placed here..
}, 1000)) {
    throw new TimeoutException("Timeout waiting for exclusive access");
}

This way the forgetting the Monitor.Exit() is not an option.

Related