2011-11-10 95 views
2

我正在创建一个类,它将具有某种键值对。目前,我有类似于以下内容:线程安全访问静态集合

private static Dictionary<Type, List<PropertyInfo>> PropertyCache { get; set; } 

这是在线程安全方法中实现的正确方法吗?出于某种原因,在这种情况下,我对对Dictionary的影响感到困扰。如果这是正确的,是否有一种不正确的方式可以证明,以便我可以在其余的代码中避免它。

另外,它应该是只读的(我只会添加 - 从集合中删除的东西)?

如果有所作为,该物业将永远被宣布为private

在此先感谢

虽然标签C#,VB中的回答都OK,我是 “双语” 可以这么说

编辑:用乔恩斯基特

经过讨论在他的回答的评论中,用法将是:

// I will do this 
PropertyCache.Add(typeof(string), new List<PropertyInfo>()); 
PropertyCache.Remove(typeof(string)); 

// I will never do this 
PropertyCache = new Dictionary<Type, List<PropertyInfo>>(); 

I永远不会遍历集合,只能通过键访问。

+1

“我只会添加 - 从集合中删除的东西”是什么意思? –

+0

@SteveDanner,例如我永远不会去'PropertyCache = new Dictionary >'只有'PropertyCache.Add(item)':) –

+0

OK,一个ReadOnlyDictionary将无法正常工作。考虑Jon Skeet的答案,IMO。 –

回答

1

使成员static使其更有可能具有跨实例成员的跨线程访问权限。请记住,static并不意味着多线程可以安全地使用它,这意味着该对象在定义它的对象的多个实例之间共享。

收藏它们实现ICollection接口可以转换为访问SyncRoot你可以用它来lock对象,以确保只有一个线程在同一时间可以执行一系列的会导致集合改变指令。 Using SyncRoot for Multithreaded Applications

lock(((ICollection)myObject).SyncRoot) 
{ 
    //Code that should be executed by only one concurrent thread 
    //This is add/insert/remove/iterate/clear/etc. 
} 

除了本手册(或更老派的方式)有其基本上做这一点,但与其他一些特殊的检查,在.NET 4提供并发对象。大多数情况下,这些对象的性能都已经过优化,您可以获得完全安全的对象。如果您在对象上使用了一组非常可控的小动作(您有1个添加,1个删除方法并且永远不会枚举整个集合,但只访问特定的已知条目),则可以使用上面较轻量级的lock()示例获得更好的表现。

您会在同时向集合中添加多个对象时看到这一点。使用并发对象的每个添加操作都是原子锁定和解锁。如果你在一个紧密的循环中运行它,你会失去一些反复获取锁的性能。如果另一个线程正在尝试读取,访问争用会变得更高一些。如果您自己使用锁定语句,则只需获取锁定,以快速,紧密的循环添加对象,然后释放锁定。希望访问该对象的线程将等待一段时间,但整体操作应该更快完成。另外请记住,差异通常非常低,不值得,并且在几乎所有情况下都属于过早优化的范畴。

3

除非您需要更改变量的值,否则您应该将其设置为只读。

如果你使用.NET 4,你应该考虑使用ConcurrentDictionary - 否则,我可能会写访问器,它只是为每个访问获取一个锁。虽然你可能使用ReaderWriterLockSlim等,我个人会用最简单的安全方法开始。

请注意,以线程安全的方式遍历字典的内容将是棘手 - 希望你不需要那样。

+0

谢谢乔恩。请你能扩展你的意思是“最简单的安全方法”,所以我有一个关于如何在Net 35应用程序中实现这个功能的想法。 –

+0

@SBlackler:最简单的方法就是锁定每个访问。将用一个例子编辑。 –

+0

@SBlackler:其实,我刚刚注意到这个值是一个列表......它不会是线程安全的* * *。你打算如何使用它?一旦填充,列表是否为只读? –

0

你所显示的是丝毫不安全的。如果多个线程可以同时插入或删除项目,则存在潜在的问题。