下面的代码将从网站调用,因此在非静态类中拥有静态字典对象需要是线程安全的。基本上,代码的目的是封装逻辑并维护perfmon计数器的生命周期,这些计数器存储在CounterContainer的实例中。构造函数被称为传入instanceName。构造函数需要检查是否已定义该instanceName的CounterContainer并将其存储在字典中。如果是这样,它可以(并且必须)使用该实例。如果没有,它会创建CounterContainer的实例,将其存储在字典中,然后使用该实例。要使用的CounterContainer的实例存储在非静态成员中,因此从那时起是线程安全的。
作为静态字典使用的唯一地方是在构造函数中,我觉得在将要访问它的时间内锁定字典是安全的吗?这是否会导致以后出现任何无法预料的问题,例如阻塞/死锁?我看不到任何东西,但过去并没有真正需要过多考虑这类事情。
我还考虑过 lock(this):,但我认为这不会起作用,因为它只会锁定正在创建的PerformanceCounters的实例,而不是基础静态字典(所以不会是线程安全的)。
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();
}
}
}
答案 0 :(得分:5)
不要不同意使用ConcurrentDictionary的建议,而是更广泛地回答:
this
,因为该代码外部的东西可以锁定对象,并且您可以轻松地获得死锁或至少锁定争用,只能通过查看类内部的代码才能找到和调用代码(和写一个人可能无法访问另一个)。出于类似原因,永远不要锁定Type
。partial
,如果使用partial
,请尝试将对象上的所有锁保留在同一位置。这里没有任何技术原因,但是当你需要考虑可以采取锁定的所有潜在地点时,它确实有帮助。答案 1 :(得分:2)
是的,它将起作用,因为_containers是静态的。
你可能也想看看ReaderWriterLockSlim,所以你想要阻止这么多(改善性能)
答案 2 :(得分:0)
在我看来,拥有一个专门用于锁定的显式对象实例是很常见的。
private readonly object containerLock = new object();
...
lock (containerLock) {
...
}
另一个提示:如果您正在使用.NET 4,请考虑使用ConcurrentDictionary
。
答案 3 :(得分:0)
是的,_containers在理论上是可以的,因为它的范围与字典实例相同,也就是说,它是静态的(显然 - 它是字典实例。)
然而,一旦您对整体设计感到担忧,您就会说这是在网站上托管的。每个asp.net worker都是一个单独的进程,因此当IIS由于空闲或其他原因而回收工作进程时,您的静态字典可能会被销毁。此外,如果您使用网络花园(每个应用程序有多个工作人员),您可能有多个字典实例。