The code below is going to be called from a website so having a static dictionary object in a non static class needs to be threadsafe. Basically the purpose of the code is to encapsulate logic and to maintain the life-time of the perfmon counter(s), which are stored in an instance of CounterContainer. The constructor is called passing in instanceName. The constructor needs to check to see if a CounterContainer for that instanceName has been defined and stored in the dictionary. If so, it can (and must) use that instance. If not it creates an instance of the CounterContainer, stores it in the dictionary and then uses that instance. The instance of the CounterContainer to be used is stored in a non static member so is thread safe from that point on.
As the only place that that the static dictionary is used is within the constructor it feels to me that it will be safe to lock on the dictionary for the duration that it will be accessed? Is this going to cause any unforeseen issues later on with anything like blocking / deadlocks? I can't see anything, but haven't really had the need to consider this sort of thing too much in the past.
I have also considered lock(this): but I don't think that would work as it would only lock the instance of PerformanceCounters being created, and not the underlying static dictionary (so would not be threadsafe).
namespace ToolKit
{
using System;
using System.Diagnostics;
using System.Collections.Generic;
public class PerformanceCounters : IPerformanceCounters
{
private static Dictionary<string, CounterContainer> _containers = new Dictionary<string, CounterContainer>();
private CounterContainer _instanceContainer;
public PerformanceCounters(string instanceName)
{
if (instanceName == null) throw new ArgumentNullException("instanceName");
if (string.IsNullOrWhiteSpace(instanceName)) throw new ArgumentException("instanceName");
// Is this the best item to lock on?
lock (_containers)
{
if (_containers.ContainsKey(instanceName))
{
_instanceContainer = _containers[instanceName];
return;
}
_instanceContainer = new CounterContainer(instanceName);
_containers.Add(instanceName, _instanceContainer);
}
}
public void Start()
{
_instanceContainer.AvgSearchDuration.Start();
}
public void FinishAndLog()
{
_instanceContainer.SearchesExecuted.Increment();
_instanceContainer.SearchesPerSecond.Increment();
_instanceContainer.AvgSearchDuration.Increment();
}
}
}