ConcurrentDictionary Pitfall - Are delegates factories from GetOrAdd and AddOrUpdate synchronized? note che AddOrUpdate non è atomico (e non può garantire che i delegati non vengano eseguiti più di una volta).atomic addorupdate (cercando di scrivere l'armadietto denominato usando il dizionario simultaneo)
Sto cercando di implementare un nome di bloccaggio implementazione utilizzando un dizionario concomitante alla here, ma dove il dizionario non dovrebbe crescere per sempre, come questo:
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);
}
}
}
Ma il problema è l'AddOrUpdate non è atomica , quindi vedo che spesso le voci non vengono rimosse in caso di contesa. Sono abbastanza sicuro che se AddOrUpdate fosse atomico, il codice sopra farebbe il suo lavoro e le voci verrebbero rimosse in modo appropriato.
Notare l'utilizzo della rimozione condizionale mediante il metodo di estensione chiave + val TryRemove (chiave, val) menzionato here. Inoltre, IntObject è un semplice wrapper oggetto mutabile di un int.
Quali sono le mie opzioni? Esistono implementazioni di dizionari simultanei che hanno 1. rimozioni atomiche (su chiave e valore) e 2. AddOrUpdate è atomico e garantisce che i delegati non vengano eseguiti più di una volta?
Hai altre idee? Mi piacerebbe che l'armadietto denominato fosse veloce ma non avesse problemi di pressione di memoria dato un namespace di lock illimitato ma con non molta contesa su un nome dato. Per quanto ne so, lo string interning locking by name cresce per sempre e non viene mai ripulito e ha altri effetti collaterali. E i mutex sono semi-lenti e hanno vari fastidi (limite di 260 caratteri).
È è possibile utilizzare un dizionario digitato come "ConcurrentDictionary>" come descritto in questa risposta http://stackoverflow.com/a/12611341/1236734 –