Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ConcurrentDictionary - broken dictionary or bad code?

Alright, so I'm running into a strange little issue and frankly I'm out of ideas. I wanted to throw this out there to see if I'm missing something that I've done wrong, or if ConcurrentDictionary isn't working correctly. Here's the code:

(Cache is a class containing the static ConcurrentDictionary Keys)

var tmp = Cache.Keys.GetOrAdd(type,
                key =>
                {
                    var keys = context.GetKeys(key);
                    if (keys.Count() == 1)
                    {
                        return new KeyInfo
                            {
                                Name = keys.First().Name,
                                Info = key.GetInfo(keys.First().Name)
                            };
                    }

                    return null;
                });

            if (tmp == null)
                Cache.Keys.TryRemove(type, out tmp);

            return tmp;

The problem is that occasionally tmp is null, causing the TryRemove line to run, yet the return null; line above is never hit. Since that return null is the only thing putting null into the dictionary and it never runs, how could tmp ever be null?


Including the Cache class (SetNames is not used by this code):

public class Cache
{
    public static ConcurrentDictionary<Type, Info> Keys = new ConcurrentDictionary<Type, Info>();
    public static ConcurrentDictionary<Type, string> SetNames = new ConcurrentDictionary<Type, string>();
}
like image 954
Madeline Trotter Avatar asked Jan 05 '12 22:01

Madeline Trotter


People also ask

Is ConcurrentDictionary thread-safe C#?

Concurrent. ConcurrentDictionary<TKey,TValue>. This collection class is a thread-safe implementation. We recommend that you use it whenever multiple threads might be attempting to access the elements concurrently.

Is ConcurrentDictionary indexer thread-safe?

It is thread-safe in the sense that the internal state of the ConcurrentDictionary will not be corrupted.

Is ConcurrentDictionary slower?

NET 5, ConcurrentDictionary appears to offer the best read performance (benchmarks indicate that it is even faster than a normal Dictionary ), so unless you have specific requirements that only CopyOnWriteDictionary fulfills (i.e. consistent "snapshot" enumeration) then you should probably use that instead.

How does ConcurrentDictionary work in C#?

ConcurrentDictionary is thread-safe collection class to store key/value pairs. It internally uses locking to provide you a thread-safe class. It provides different methods as compared to Dictionary class. We can use TryAdd, TryUpdate, TryRemove, and TryGetValue to do CRUD operations on ConcurrentDictionary.


2 Answers

tmp can be null if you get anything other than a single item set back from context.GetKeys(key). In that case, keys.Count() != 1, and a null item will be inserted into Cache.Keys for the specified key (and returned from GetOrAdd, and assigned to tmp).

EDIT: Just thought of another possibility. What datatype is the key? Is it some kind of custom class? It looks like it is. If so, have you implemented Equals and GetHashcode properly?

like image 130
Chris Shain Avatar answered Sep 28 '22 08:09

Chris Shain


I should have closed this a while ago but I completely forgot about it. The example is not thread safe because of TryRemove, but that was only added for debugging purposes. I ended up getting around the problem by rewriting it, so perhaps some of the comments about the code somehow being stale are correct. The code no longer exists to confirm, however.

I'm chalking this one up to user error (my own of course). Thanks for everyone's time!

like image 24
Madeline Trotter Avatar answered Sep 28 '22 08:09

Madeline Trotter