C# 队列有时会损坏

C# 队列有时会损坏,c#,.net,queue,C#,.net,Queue,我正在运行一个多线程程序,看到一些奇怪的行为。我将首先尝试在下面稍微解释一下架构 该应用程序基本上有一组大小为30的队列。数组中的每个队列都由一个线程处理。外部ome外部线程将根据id的mod不断向队列数组中添加实体 例如:如果实体id=100,它将进入100%30=10队列 我面临的问题是,有时一个id=100的实体被添加到队列中,但处理线程将一个完全不同的实体从队列中退出,但它属于同一队列。e 例如:外部线程使实体id=50的队列进入第20个队列,但线程将使id=80的实体退出队列 这只发生

我正在运行一个多线程程序,看到一些奇怪的行为。我将首先尝试在下面稍微解释一下架构

该应用程序基本上有一组大小为30的队列。数组中的每个队列都由一个线程处理。外部ome外部线程将根据id的mod不断向队列数组中添加实体

例如:如果实体id=100,它将进入100%30=10队列

我面临的问题是,有时一个id=100的实体被添加到队列中,但处理线程将一个完全不同的实体从队列中退出,但它属于同一队列。e

例如:外部线程使实体id=50的队列进入第20个队列,但线程将使id=80的实体退出队列

这只发生在生产环境中,无论如何都无法模拟。它很少在没有任何触发的情况下发生,比如在应用程序重启后

我怀疑这可能是因为我在请求/解除请求时没有使用任何锁导致数据损坏


我想知道是否有人曾经遇到过类似的问题,或者有没有关于如何避免这种情况的建议。添加锁是前进的一个方向,但在我开始之前,我想确认问题的根源。

您说您没有使用任何锁,您使用的是队列类吗?如果是这样,您应该在这些场景中使用该类,它位于System.Collections.Concurrent命名空间中

我怀疑这可能是因为我没有使用任何锁 当请求/取消请求导致数据损坏时

是的,它是数据竞争的来源。如果您的多个线程正在公共的、未受保护的数据结构上生成和使用对象,则会随机出现您描述的效果。数据竞争“更多地发生在生产中”是典型的,因为您使用的代码更优化,在更快的机器上,并且通常具有更多的线程,从而增加了数据竞争的可能性

使用锁定机构(例如)保护公共结构的每个通道。MSDN还提供了有关的多个教程

最终,如@罗南所指出的,考虑使用从Staly.St藏品中收集的集合。并发< /代码>:它们的访问已经是线程安全的,并且它们针对多线程方案进行了优化,使您的工作变得更加容易。p> 编辑:


当性能重要时,总是考虑分析这两种方法(使用手动保护的集合VS从代码>系统。集合。并发< /COD>)< /P>是否将队列中的线程使用任何类型的逻辑,或者它们是否直接基于分配队列?Dequeing中没有逻辑它们针对特定类型的多线程场景进行了优化。当生产者和消费者在同一线程上处于混合使用场景时,
ConcurrentQueue
可能比周围有锁的
队列要慢得多;在多核系统中,这一点被夸大了。@MichaelJ.Gray关于如何解决这个问题,你有其他建议吗(似乎缺乏详细的架构建议…)@TetsujinnoOni我肯定会同意quantdev的建议。我还将给出标准的“获取一本关于线程的书”类型响应。锁定通常是相当快的,如果不是,那么专门的无锁负载平衡或优先级队列(我猜他试图实现的)非常难以正确实现,但可能是替代方案。分析是确定瓶颈所在的好方法,我敢打赌这不是锁争用。过了很久再回到这个线程。。。我仍然无法确定问题所在。分析听起来像是一种前进的方式,但对我来说这不是一个容易的选择,因为问题只发生在生产环境中,而分析则没有选择。但我仍然想在另一个环境中尝试,看看是否能找到任何模式@Gray,你推荐什么工具来评测.NET4.5应用程序?基本上是一个只提供链接的答案-1直到解释为什么<代码>队列类在不带锁的并发环境中是不安全的。似乎是对我自己的回答,它的名字和命名空间使它显而易见。我不认为它本身是有用的。它没有解释为什么最初的代码是错误的,也没有提供任何人都可以使用的独立解决方案。如果有人不了解锁定机制以及它的重要性,那么您的答案可能会被忽略,并且无法提供尽可能多的帮助。如果你的目标是帮助别人,那为什么不改进呢?反正你就快到了。我所做的只是告诉你我为什么选择投你反对票;为stackoverflow上的否决票提供解释是一种常见的礼貌,我已经告诉过你了。