这是一篇翻译,专门介绍Dictionary线程安全问题,原文网址如下

http://www.grumpydev.com/2010/02/25/thread-safe-dictionarytkeytvalue/

翻译的不对之处,请指正。

介绍

一个宠物项目,我目前正在研究中需要使用内部字典来存储“注册”的数据,这是一个相当普遍的要求。 对于这个特殊的项目,.net 3.5中,我想至少尝试使其“线程安全”的,

着眼于将其移动到ConcurrentDictionary,.NET4中保证线程不仅是安全的,而且具有更精细的锁提高多线程性能。

一个再简单不过的例子,却有许多人犯着这样的错误。

1.只是锁定写入?

很明显,我们需要围绕着写同步原语syncronisation primitive类型的操作,但第一印象可能会使你认为读应该没问题-----尤其是如果我们坚持优先TryGetValue模式,而不是“如果它存在,那么得到的值”:

            object myValue;  // This is obviously not thread safe.
// Something else can alter the collection
// between ContainsKey and reading the
// value.
if (dictionary.ContainsKey("Testing"))
{
myValue = dictionary["Testing"];
}
//Using TryGetValue looks safe though?
//Doesn't it?!
if (!dictionary.TryGetValue("Testing", out myValue)) throw new KeyNotFoundException();

不幸的是,如果使用Reflector查看器,看看TryGetValue是如何实现的,作为上面的第一种方法,很明显它具有完全相同的并发问题:

 public bool TryGetValue(TKey key, out TValue value)
{
int index = this.FindEntry(key);
if (index >= )
{
value = this.entries[index].value;
return true;
}
value = default(TValue);
return false;
}

2.因此,我将锁定读取和写入?

下一个显而易见的方法是要找到我们的代码中无处不在的Dictionary,用于读取或写入,并使用同步原语syncronisation primitive,例如锁 ,以确保我们任何时候只在单个线程访问它:

        private readonly object padlock = new object();
private readonly Dictionary<string, object> dictionary = new Dictionary<string, object>(); private void Test()
{
object myValue; // Now we lock before we do anything lock (padlock)
{ if (dictionary.ContainsKey("Testing"))
{
myValue = dictionary["Testing"];
}
}
lock (padlock)
{ if (!dictionary.TryGetValue("Testing", out myValue)) { } }
}

很简单,但你依赖锁定周围的每一个访问,这不仅难看,而且如果你错过了一个,也可能容易出现错误。  因此,一旦把我们代码迁移到.NET 4。在新的ConcurrentDictionary,我们将不得不通过代码并依次取出每个锁 – 这工作相当辛苦!

3.组合(组合设计模式的实现)

在这种方法中,总结了我们在自己的类中使用讨厌地非线程安全的Dictionary,让我使用想用的方法,并采取相应的任何锁。 这个类只实现了“array” 的访问和TryGetValue,但是这个方法足够用了:

  public class SafeDictionary<TKey, TValue>
{ private readonly object _Padlock = new object();
private readonly Dictionary<TKey, TValue> _Dictionary = new Dictionary<TKey, TValue>();
public TValue this[TKey key]
{
get
{
lock (_Padlock)
{
return _Dictionary[key];
}
}
set
{
lock (_Padlock)
{
_Dictionary[key] = value;
}
}
}
public bool TryGetValue(TKey key, out TValue value)
{
lock (_Padlock)
{
return _Dictionary.TryGetValue(key, out value);
}
}
}

当我们防止任何直接进入Dictionar和每当我们需要访问它并在内部使用我们的锁的时候,我们现在可以使用代码SafeDictionary无需担心并发问题 - 无论是读和写操作!

4.到 .Net 4 ?

正如我前面提到的,.NET 4将支持数个“线程安全”的集合,其中包括Dictionary,在新的System.Collections.Concurrent命名空间 。 因此我们有自己实现的SafeDictionary,有以下几个特点:

ž   我们可以通过我们的代码并替换所有引用SafeDictionary与ConcurrentDictionary。在我们的主代码中没有任何锁,以至于我们可以这个直接替换。

ž   我们可以改变我们的SafeDictionary内部使用一个ConcurrentDictionary,并删除所有的内部锁。

ž   如果我们不介意使用额外的方法,我们可以删除所有来自SafeDictionary实例和继承ConcurrentDictionary:

public class SafeDictionary<Tkey, TValue> : ConcurrentDictionary<Tkey, TValue>
{ }

5.结论

相当长的博客文章提交一个相当简单的问题,但有时候碰巧碰到简单的并发可以是失误和头痛的根源。 一旦.NET 4中到达其​​并发集合 , 并行扩展和并行调试选项有望至少*这个头痛的事情会自行消失。

“线程安全的” Dictionary(TKey,TValue)的更多相关文章

  1. C#字典 Dictionary<Tkey,Tvalue> 之线程安全问题 ConcurrentDictionary<Tkey,Tvalue> 多线程字典

    ConcurrentDictionary<Tkey,Tvalue>  Model #region 程序集 mscorlib, Version=4.0.0.0, Culture=neutra ...

  2. .net源码分析 – Dictionary<TKey, TValue>

    接上篇:.net源码分析 – List<T> Dictionary<TKey, TValue>源码地址:https://github.com/dotnet/corefx/blo ...

  3. .NET中Dictionary<TKey, TValue>浅析

    .NET中Dictionary<TKey, Tvalue>是非常常用的key-value的数据结构,也就是其实就是传说中的哈希表..NET中还有一个叫做Hashtable的类型,两个类型都 ...

  4. C# .Net 中字典Dictionary<TKey,TValue>泛型类 学习浅谈

    一.综述: Dictionary<TKey,TValue>是在 .NET Framework 2.0 版中是新增的.表示键值对的集合,Dictionary<TKey,TValue&g ...

  5. Dictionary<Tkey.TValue>与SortedList

    一.概述 表示Key/Value集合,可以添加删除元素,允许按Key来访问元素.是Hashtable的泛型等效类. 它需要一个相等实现来确定键是否相等,可以使用实现了IEqualityComparer ...

  6. c# 扩展方法奇思妙用基础篇五:Dictionary<TKey, TValue> 扩展

    Dictionary<TKey, TValue>类是常用的一个基础类,但用起来有时确不是很方便.本文逐一讨论,并使用扩展方法解决. 向字典中添加键和值 添加键和值使用 Add 方法,但很多 ...

  7. Dictionary<TKey, TValue> 类

    C# Dictionary<TKey, TValue> 类 Dictionary<TKey, TValue> 泛型类提供了从一组键到一组值的映射.字典中的每个添加项都由一个值及 ...

  8. C# 字典 Dictionary<Tkey,Tvalue>

    最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来.我们都知道计算机技术发展日新月异,速度惊人的快,你我稍不留神,就会被慢慢淘汰!因此:每日不间断的学习是避免被 ...

  9. 巧用Dictionary<TKey,TValue>,完成客户需求

    前几天与客户沟通一个项目,客户对其中某个模块提了一个需求. 把从数据库中取出的对物品的统计重新拆分重新统计.鉴于用文字不能清除的表达需求,我将该需求画出来,便于理解. 需求如下图: 就是A,B,C D ...

随机推荐

  1. web前端常用的linux命令(在git命令行使用)

    cd (文件目录): 回到上一层目录 cd .. 回到根目录 cd / mkdir(新建文件夹) 下面的命令在当前目录新建了文件夹css html js 3个文件夹 mkdir css html js ...

  2. app接口开发(php)

    1.JSON方式封装通信接口: 封装: response.php <?php // JSON方式封装通信接口 // 定义 response类 class Response { // 定义一个静态 ...

  3. 开启GodMode

    上帝模式的开启方法:首先你可以在任何地方创建一个新文件夹,这个操作对于几乎所有电脑用户来说都非常简单,然后重要的是,将这个新文件夹重命名为 “GodMode.{ED7BA470-8E54-465E-8 ...

  4. (转)C的代码是如何变成程序的

    原文链接:http://blog.csdn.net/fz_ywj/article/details/8769825 C语言是一门典型的编译语言,源代码文件需要编译成目标代码文件才能运行.可以认为程序文件 ...

  5. cordova开发自己定义插件

    以下是自己定义cordova插件的基本入门.做插件的小白可以參考一下哈,兴许会更新插件的进阶博客,希望大家可以共同学习共同进步 1.环境搭建 cordova插件开发前须要安装一些软件和配置环境 1.1 ...

  6. Angularjs学习笔记2_添加删除DOM元素

    1.调用element方法     angular.element(html) 把字符串或dom对象转化成一JQuery对象, angular.element(document.getElementB ...

  7. spark-streaming的checkpoint机制源码分析

    转发请注明原创地址 http://www.cnblogs.com/dongxiao-yang/p/7994357.html spark-streaming定时对 DStreamGraph 和 JobS ...

  8. virtualenv下使用matplotlib

    Unable to “import matplotlib.pyplot as plt” in virtualenv   (PyMVPA) SimilarFacedeMacBook-Pro:PyMVPA ...

  9. Chrome插件之一键保存网页为PDF1.1发布

    最新版本:V1.1 下载地址:http://download.csdn.net/detail/bdstjk/5722317 http://pan.baidu.com/share/link?sharei ...

  10. org.mockito.exceptions.misusing.CannotStubVoidMethodWithReturnValue

    错误原因:mock的时候,不能mock重载的方法 解决方法:直接mock它的父类的方法 org.mockito.exceptions.misusing.CannotStubVoidMethodWith ...