在什么条件下TryDequeue和类似的System.Collections.Concurrent收集方法会失败

问题描述

|| 我最近注意到,在System.Collections.Concurrent命名空间中包含的集合对象中,通常看到“ 0”而不是“ 1”。 这是什么原因?我认为这与锁定有关吗? 因此,我想知道在什么条件下尝试(例如)从堆栈,队列,袋子等中取出项目失败。     

解决方法

System.Collections.Concurrent
名称空间中的集合被认为是线程安全的,因此可以使用它们编写在线程之间共享数据的多线程程序。 在.NET 4之前,如果多个线程可能正在访问单个共享集合,则必须提供自己的同步机制。每次修改其元素时,都必须锁定该集合。您可能还需要在每次访问(或枚举)集合时都将其锁定。这是最简单的多线程方案。某些应用程序会创建后台线程,这些线程会随着时间的推移将结果传递到共享集合中。另一个线程将读取并处理这些结果。您需要在线程之间实现自己的消息传递方案,以在新结果可用时以及新结果被消耗时互相通知。 “ 2”中的类和接口为那些和其他常见的多线程编程问题(以无锁方式跨线程共享数据)提供了一致的实现。
Try<something>
具有语义-尝试执行该操作并返回操作结果。 “ 5”语义通常使用抛出异常的机制来指示错误,该错误可能无效。作为示例,它们可以返回false, 如果尝试添加新元素,则可能已经在
ConcurentDictionary
中包含了; 如果您尝试从集合中获取元素,则该元素可能不存在; 如果您尝试更新元素,那么可能已经有更新的元素了,因此方法确保它仅更新要更新的元素。 尝试阅读: 并行编程模式:使用.NET Framework 4理解和应用并行模式-最佳入门; .NET Framework中的并行编程; 阅读有关并发的文章 .NET Framework 4中的线程安全集合及其性能特征     ,失败意味着什么? 请看以下示例:
var queue = new Queue<string>();
string temp = queue.Dequeue();
// do something with temp
上面的代码带有异常,因为我们尝试从空队列中出队。现在,如果您使用
ConcurrentQueue<T>
代替:
var queue = new ConcurrentQueue<string>();
string temp;
if (queue.TryDequeue(out temp))
{
    // do something with temp
}
上面的代码不会引发异常。队列仍然无法使项目出队,但是代码不会以引发异常的方式失败。真正的用途在多线程环境中变得很明显。非并发“ 10”的代码通常看起来像这样:
lock (queueLock)
{
    if (queue.Count > 0)
    {
        string temp = queue.Dequeue();
        // do something with temp   
    } 
}
为了避免出现竞争状况,我们需要使用锁来确保在检查
Count
和调用
Dequeue
之后的时间内队列没有任何反应。使用
ConcurrentQueue<T>
,我们实际上不需要检查
Count
,而是可以调用
TryDequeue
。 如果检查
Systems.Collections.Concurrent
命名空间中的类型,您会发现其中许多包装通常依次调用的两个操作,并且传统上需要锁定(
ConcurrentQueue<T>
中的
Count
,然后是
Dequeue
ConcurrentDictionary<TKey,TValue>
中的
GetOrAdd
替换了调用
ContainsKey
的序列,添加一个项目并获取它,依此类推)。     ,例如,如果没有什么“出队”,则此“ Try-Pattern”通常在FCL和BCL元素中使用。这与锁定无关,并发集合大多数(至少应该)没有锁定就实现了...