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>();
}
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.
It is thread-safe in the sense that the internal state of the ConcurrentDictionary will not be corrupted.
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.
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.
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?
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With