Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any downsides to locking a collection vs. a syncRoot?

I'm wondering if there are any downsides to locking over a collection such as a List<T>, HashSet<T>, or a Dictionary<TKey, TValue> rather than a simple object.

Note: in the following examples, that is the only place where the locks occur, it's not being locked from multiple places, but the static method may be called from multiple threads. Also, the _dict is never accessed outside of the GetSomething method.

My current code looks like this:

private static readonly Dictionary<string, string> _dict = new Dictionary<string, string>();
public static string GetSomething(string key)
{
    string result;
    if (!_dict.TryGetValue(key, out result))
    {
        lock (_dict)
        {
            if (!_dict.TryGetValue(key, out result))
            {
                _dict[key] = result = CalculateSomethingExpensive(key);
            }
        }
    }
    return result;
}

Another developer is telling me that locking on a collection will cause issues, but I'm skeptical. Would my code be more efficient if I do it this way?

private static readonly Dictionary<string, string> _dict = new Dictionary<string, string>();
private static readonly object _syncRoot = new object();
public static string GetSomething(string key)
{
    string result;
    if (!_dict.TryGetValue(key, out result))
    {
        lock (_syncRoot)
        {
            if (!_dict.TryGetValue(key, out result))
            {
                _dict[key] = result = CalculateSomethingExpensive(key);
            }
        }
    }
    return result;
}
like image 454
ckknight Avatar asked Nov 29 '22 19:11

ckknight


1 Answers

If you expose your collections to the outside world, then, yes this can be a problem. The usual recommendation is to lock on something that you exclusively own and that can never be locked unexpectedly by code that is outside your influence. That's why generally it's probably better to lock on something that you'd never even consider exposing (i.e. a specific lock object created for that purpose). That way, when your memory fails you, you'll never probably not get unexpected results.

To answer your question more directly: Adding another object into the mix is never going to be more efficient, but placing what is generally regarded as good coding practice before some perceived, but unmeasured efficiency might be an optmisation occurring prematurely. I favour best practice until it's demonstrably causing a bottleneck.

like image 132
spender Avatar answered Dec 05 '22 08:12

spender