The class below raises an event for every new “dataKey” registered and raises an event when a “dataKey” is deregistered and count for that “dataKey is zero.
This class aims to be threadsafe and I am trying to make this as performant as possible.
My question is; in the Deregister method can I somehow remove the 2nd lookup when I update the value (the _data[dataKey] = currentCountValue;)?
I can’t simple update the currentCountValue variable as the value is updated on the local stack only and not in the Dictionary.
Or can you sugguested any performance improvements? I don’t think I can remove the lock and use CAS operations (Interlocked methods) to update the count as the dictionary is not threadsafe for updates when used like this … right?
/I am using c# 3.0.
Thanks for your time.
public sealed class DataCounter
{
public event EventHandler NewKeyEvent;
public event EventHandler ZeroCountEvent;
private readonly Dictionary<string, int> _data = new Dictionary<string, int>();
public void Register(string dataKey)
{
lock (_data)
{
if (_data.ContainsKey(dataKey))
{
_data[dataKey]++;
}
else
{
_data.Add(dataKey, 1);
if (NewKeyEvent != null) NewKeyEvent(this, null);
}
}
}
public void Deregister(string dataKey)
{
lock (_data)
{
int currentCountValue;
if (_data.TryGetValue(dataKey, out currentCountValue))
{
if (currentCountValue > 0)
{
currentCountValue--;
_data[dataKey] = currentCountValue;
}
if (currentCountValue == 0)
{
if (ZeroCountEvent != null) ZeroCountEvent(this, null);
}
}
}
}
}
As a thought – if you don’t want to have to do the “set” via an indexer, you could move the counter out onto a class?
Then have a
Dictionary<string,CounterBox>. You can now updateCountoutside of the dictionary, and only callRemove(dataKey)when.Countis zero. This will have an extra de-reference, but you won’t have to assign via the indexer.As for which is faster: you’d need to profile.
Something like: