Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this non-locked TryGetValue() dictionary access thread-safe?

private object lockObj = new object();

private Dictionary<int, string> dict = new Dictionary<int, string>();

public string GetOrAddFromDict(int key)
{
    string value;

    // non-locked access:
    if (dict.TryGetValue(key, out value))
        return value;

    lock (this.lockObj)
    {
        if (dict.TryGetValue(key, out value))
            return value;

        string newValue = "value of " + key; // place long operation here
        dict.Add(key, newValue);

        return newValue;
    }
}

Question a: Is it thread-safe? If yes, why?

Question b: How is this double-TryGetValue() pattern called?

like image 466
moop Avatar asked Jul 18 '11 19:07

moop


3 Answers

a) This is not thread-safe, as the underlying Dictionary itself is not thread safe. If another thread is calling Add at the same time, undefined behavior can occur.

b) This is effectively an attempt at double-checked locking.

I would recommend using the ConcurrentDictionary class instead, as it's designed for this scenario. Another option would be to use a ReaderWriterLockSlim (or ReaderWriterLock), if you're not targetting .NET 4.0.

like image 163
Reed Copsey Avatar answered Oct 12 '22 23:10

Reed Copsey


Question a: Is it thread-safe? If yes, why?

Not only is it not thread safe; it will also throw with NullReferenceException if accessed while another thread is reorganizing the hash buckets. The lock statement is wicked fast, don't avoid it.

Question b: How is this double-TryGetValue() pattern called?

It's called a 'bug' by most people ;)

like image 25
csharptest.net Avatar answered Oct 13 '22 00:10

csharptest.net


Sadly, no.

I carry around a custom HashMap that has this property.

The defect is in the rehash() function.

like image 39
Joshua Avatar answered Oct 13 '22 00:10

Joshua