views:

60

answers:

2

I have a function that returns an entry on a dictionary, based on the Key (name) and if it doesn't exist, returns a newly created one.

The question I have is with the "double lock" : SomeFunction locks the _dictionary, to check for the existance of the key, then calls a function that also locks the same dictionary, it seems to work but I am not sure if there is a potential problem with this approach.

public Machine SomeFunction(string name) 
{
    lock (_dictionary)
    {
        if (!_dictionary.ContainsKey(name))
                    return CreateMachine(name);
        return _dictionary[name];
    }
}


private Machine CreateMachine(string name)
{
    MachineSetup ms = new Machine(name);
    lock(_dictionary)
    {
        _ictionary.Add(name, ms);
    }
    return vm;
}
+4  A: 

That's guaranteed to work - locks are recursive in .NET. Whether it's really a good idea or not is a different matter... how about this instead:

public Machine SomeFunction(string name) 
{ 
    lock (_dictionary)
    {
        Machine result;
        if (!_dictionary.TryGetValue(name, out result))
        {
            result = CreateMachine(name);
            _dictionary[name] = result;
        }
        return result;
    } 
}

// This is now *just* responsible for creating the machine,
// not for maintaining the dictionary. The dictionary manipulation
// is confined to the above method.
private Machine CreateMachine(string name)
{
    return new Machine(name);
}
Jon Skeet
@Jon Skeet: Only to verify for myself, one shouldn't try to get the value instead of locking the Dictionary right away? Like you lock only when the TryGetValue() method returns false?
Will Marcouiller
@Will Marcouiller - Your scheme would allow one thread to modify the dictionary while another thread is reading it. If the dictionary class were specifically designed to allow that, then some scheme along those lines may be possible (with an extra TryGetValue after taking the lock). However, collections are not generally designed to be used in this manner, and the built-in Dictionary class is among those that should never be read and written to at the same time.
Jeffrey L Whitledge
Thanks for this great explanation Jeffrey! I would have sworn precisely that some of my colleagues have already used a TryGetValue() before, and after the lock()'ing the Collection. This might have been a bad usage from them then. Thanks! I shall remember that. =)
Will Marcouiller
+1  A: 

No problem here, the lock is re-entrant by the same thread. Not all sync objects have thread affinity, Semaphore for example. But Mutex and Monitor (lock) are fine.

Hans Passant