Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ConcurrentDictionary对象-通过不同线程进行读写_C#_Multithreading_Thread Safety - Fatal编程技术网

C# ConcurrentDictionary对象-通过不同线程进行读写

C# ConcurrentDictionary对象-通过不同线程进行读写,c#,multithreading,thread-safety,C#,Multithreading,Thread Safety,我想在我的应用程序中使用ConcurrentDictionary,但首先我需要确保我正确理解它的工作原理。在我的应用程序中,我将有一个或多个线程写入或删除字典。并且,我将有一个或多个从字典中读取的线程。可能,所有这些都是同时发生的 ConcurrentDictionary的实现负责实现这一点所需的所有锁定,而我不需要提供自己的锁定,这对吗?换句话说,如果一个线程正在向字典写入或从字典中删除,那么一个读取线程(或另一个写入线程)将被阻止,直到更新或删除完成 非常感谢 换句话说,如果一个线程正在向字

我想在我的应用程序中使用ConcurrentDictionary,但首先我需要确保我正确理解它的工作原理。在我的应用程序中,我将有一个或多个线程写入或删除字典。并且,我将有一个或多个从字典中读取的线程。可能,所有这些都是同时发生的

ConcurrentDictionary的实现负责实现这一点所需的所有锁定,而我不需要提供自己的锁定,这对吗?换句话说,如果一个线程正在向字典写入或从字典中删除,那么一个读取线程(或另一个写入线程)将被阻止,直到更新或删除完成

非常感谢

换句话说,如果一个线程正在向字典写入或从字典中删除,那么一个读取线程(或另一个写入线程)将被阻止,直到更新或删除完成

我不相信它会堵塞——它只是安全的。不会有任何腐败——你只需要在读是否看到写方面进行竞争

从a:

ConcurrentDictionary
在添加或更新字典中的数据时使用细粒度锁定,但对于读取操作,它完全没有锁定。通过这种方式,它针对从字典中读取是最频繁操作的场景进行了优化


当前的实现混合使用了条带锁(我在昨天的一次会议上回答某人时建议的技术),并且非常认真地思考操作不可能导致并发操作出现问题或由并发操作导致问题的情况(有很多,但是如果你使用它们,你必须非常确定)

因此,如果同时在并发字典上执行多个操作,则可以执行以下每个操作:

  • 甚至没有线程锁定,但一切都正常发生
  • 有些线程锁定,但它们锁定的是不同的东西,并且没有锁争用
  • 一个或两个线程彼此之间存在锁争用,并且速度会减慢,但对性能的影响小于存在单个锁时的影响
  • 一个或两个线程需要锁定整个线程一段时间(通常用于内部调整大小),这会阻止在上面的案例3中可能被阻止的所有线程,尽管有些线程可以继续运行(那些读取的线程)
  • 所有这些都不涉及脏读,而脏读只是一个与锁定模糊相关的问题(我自己的并发字典形式根本不使用锁,也没有脏读)

    此线程安全性不适用于代码完成的批处理(如果先读取值,然后再写入值,则在完成写入之前读取的值可能已更改),但请注意,
    ConcurrentDictionary
    上的单个方法可以满足一些需要对
    Dictionary
    进行两次调用的常见情况(
    GetOrAdd
    AddOrUpdate
    使用
    Dictionary
    执行两个调用,这样它们就可以原子化完成-不过请注意,某些重载中涉及的
    Func
    可能会被多次调用)

    因此,
    ConcurrentDictionary
    没有额外的危险,因此您应该选择以下选项:

    如果您必须锁定与
    ConcurrentDictionary
    提供的内容不匹配的某些批操作,例如:

    lock(lockObj)
    {
      var test = dict[key1];
      var test2 = dict[key2];
      if(test < test2 && test2 < dict[key3] && SomeOtherBooleanProducer())
        dict[key4] = SomeFactoryCall(key4);
    }
    
    锁(lockObj)
    {
    var测试=dict[key1];
    var test2=dict[key2];
    if(test
    然后您必须锁定
    ConcurrentDictionary
    ,虽然可能有一种方法可以将其与它提供的并发支持结合起来,但可能不会,所以只需使用带有锁的
    Dictionary

    否则,它将归结为并发命中的数量。如果你大部分时间只会有一个线程命中字典,但你需要防止并发访问的可能性,那么你肯定应该使用带锁的
    字典。如果你会有六个或更多线程无法访问字典线程正在命中字典,那么您肯定应该选择
    ConcurrentDictionary
    (如果它们很可能命中相同数量的键,那么请查看我的版本,因为这是一种性能更好的情况)

    很难说“少”线程和“多”线程之间的中间点在哪里。我想说的是,如果定期有两个以上的线程,那么使用
    ConcurrentDictionary
    。如果没有其他问题,在项目的整个生命周期中,并发性的需求往往会增加,而不是减少


    编辑:为了回答您给出的关于一个作者和一个读者的特定案例,根本不会有任何阻塞,因为这是安全的,原因大致相同,即多个读者和一个作者在
    哈希表上是安全的,尽管
    ConcurrentDictionary
    在几个方面都超出了这一点。

    谢谢。听起来好像是有可能的允许“脏读”(使用SQL术语)。对于我的应用程序,这是可以的。我想如果我想完全避免这种可能性,我不会使用ConcurrentDictionary,我会使用非并发字典并实现我自己的锁定。@RandyMinder:不,我认为脏读是不可能的-即使锁定了,你仍然会有数据竞争,不是吗?要么读取发生在写入之前e、 或者它发生在之后。所有的无锁意味着在读取之前开始的写入在读取之前仍然看不到。我相信在读取开始之前结束的写入应该总是可见的。我可以很容易地对此进行测试以找出答案。但是,就我而言,这不是问题。ConcurrentDictionary的实现方式将