views:

41

answers:

2

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.

+4  A: 

The reason why is that the Monitor methods all take a System.Object parameter. When you pass in a bool a box is required to convert to Object. The box operation produces a new System.Object value for each call. So the TryEnter and Exit methods see different objects and results in the exception.

When _locked was typed to Object there was no need for a box. Hence the TryEnter and Exit methods see the same object and can function correctly.

A few other comments about the code

  • TryEnter must be paired with Exit in all cases and for sanity sake the Exit call should be in a finally block. Otherwise you're inviting a deadlock scenario
  • The _locked variable is only set to false in the face of an exception. If execution does not produce an exception it will remain true and no thread will ever again enter the if block.
JaredPar
O yeah boxing sure. But isn't bool type derived from System.Object? So it is derived from Object, but nevertheless when a conversion to Object is met somewhere a boxing operation is used? Is this statement correct?
Captain Comic
@Captain, when a value type of any kind, `bool` included, is used in a location typed to `System.Object` or an interface a boxing operation will occur.
JaredPar
+1  A: 

Setting the timeout on a montior to 0 can help implement the behaviour you want. Use a globally declared object to lock against.

static object var mylock = new object();

....

if (Monitor.TryEnter(mylock, 0))
{
    try
    {
           // Do work
    }
    finally
    {
        Monitor.Exit(mylock);
    }
}
Andrew
Monitor.TryEnter(mylock, 0) is the same as Monitor.TryEnter(mylock) as far as I can see in reflector.
Chris