问题描述
||
我最近注意到,在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元素中使用。这与锁定无关,并发集合大多数(至少应该)没有锁定就实现了...