ConcurrentDictionary Pitfall - Are delegated factories from GetOrAdd and AddOrUpdate synchronized? notes that AddOrUpdate is not atomic (and cannot guarantee that delegates will be run more than once).
I am trying to implement a name block implementation using a parallel dictionary a la here , but where the dictionary should not grow forever, for example:
public class ConcurrentDictionaryNamedLocker : INamedLocker { // the IntObject values serve as the locks and the counter for how many RunWithLock jobs // are about to enter or have entered the critical section. private readonly ConcurrentDictionary<string, IntObject> _lockDict = new ConcurrentDictionary<string, IntObject>(); private static readonly IntObject One = new IntObject(1); private readonly Func<string, IntObject, IntObject> _decrementFunc = (s, o) => o - 1; private readonly Func<string, IntObject, IntObject> _incrementFunc = (s, o) => o + 1; private readonly Func<string, IntObject> _oneFunc = s => new IntObject(1); private readonly Func<string, IntObject> _zeroFunc = s => new IntObject(0); public TResult RunWithLock<TResult>(string name, Func<TResult> body) { name = name.ToLower(); TResult toReturn; lock (_lockDict.AddOrUpdate(name, _oneFunc, _incrementFunc)) { toReturn = body(); if (!_lockDict.TryRemove(name, One)) _lockDict.AddOrUpdate(name, _zeroFunc, _decrementFunc); } return toReturn; } public void RunWithLock(string name, Action body) { name = name.ToLower(); lock (_lockDict.AddOrUpdate(name, _oneFunc, _incrementFunc)) { body(); if (!_lockDict.TryRemove(name, One)) _lockDict.AddOrUpdate(name, _zeroFunc, _decrementFunc); } } }
But the problem is that AddOrUpdate is not atomic, so I see that often records are not deleted when there is competition. I am sure, however, that if AddOrUpdate was atomic, the above code would do its job and the records would be deleted accordingly.
Note the use of conditional deletion by the key extension method + val TryRemove (key, val) mentioned here . In addition, IntObject is a simple replaceable wrapper for an int object.
What are my options? Are there any parallel dictionary implementations that have 1. atomic conditional (by key and value) deletion and 2. AddOrUpdate is atomic and ensures that delegates are not run more than once?
Are there any other ideas? I would like the named locker to be fast, but not have problems with memory pressure, given the unlimited namespace of the names, but with a little controversy over the given name. As far as I know, lowercase interning by name grows forever and never gets cleaned up and has other side effects. And mutexes are semi-slow and have various annoyances (260 char limit).