C#多线程

C#多线程,c#,multithreading,C#,Multithreading,请看下面的代码。假设这是整个类。我没有遗漏任何代码。这就是它所做的一切 如果我在主程序循环中实例化这个类并不时调用myExample.Add(无论什么),我是否需要担心由于没有锁定Dequeue()和Enqueue()而导致的任何问题 公共类示例 { 专用队列q=新队列(); 公共示例() { 新线程(()=> { while(true) { 如果(此质量计数>0) { var item=this.q.Dequeue(); } 睡眠(1); } }).Start(); } 公共无效添加(T va

请看下面的代码。假设这是整个类。我没有遗漏任何代码。这就是它所做的一切

如果我在主程序循环中实例化这个类并不时调用myExample.Add(无论什么),我是否需要担心由于没有锁定Dequeue()和Enqueue()而导致的任何问题

公共类示例
{
专用队列q=新队列();
公共示例()
{
新线程(()=>
{
while(true)
{
如果(此质量计数>0)
{
var item=this.q.Dequeue();
}
睡眠(1);
}
}).Start();
}
公共无效添加(T val)
{
这个.q.Enqueue(val);
}
}
如果与此.q.Dequeue()同时调用此.q.Enqueue(val),会发生什么情况?

这取决于:如果您使用多个线程调用该示例,那么在检查队列计数和退出队列之间将有一个竞争条件。例如

T1 Call Example
T2 Call Example
T2 check Q.Count > 0 (yes)
T1 check Q.count > 0 (yes)
T2 dequeue
T1 dequeue OOPS!
若你们不使用多个线程来调用这个例子,那个么你们就不会有问题,因为你们不在乎你们去掉了什么,只在乎你们去掉了什么。如果您关心自己的表现,那么Add和Example之间的竞争条件将再次成为一个问题。

我假设

this.queue.Enqueue(val);
你是说

this.q.Enqueue(val);
?

如果是这样,那么是的,您需要执行某种类型的锁定。集合本身并不是线程安全的。考虑到你总是从一个线程中删除,而总是从另一个线程中添加,这也许可以,但为什么不小心呢?

Chris

添加一个私有静态字段

readonly static object lockObject = new object();
将出列和入列用

lock(lockObject)
{
  //do stuff
}

对于您的lambda,将其置于循环之外

,因为您正在通过Dequeue方法写入队列,所以确实需要锁定它。队列对于多个读卡器而不是多个写卡器来说是线程安全的。

我不明白为什么您认为它可能是安全的


我的担心/假设是,同时进入队列和退出队列(从两个不同的线程)可能会损坏队列实例的内部状态。

MSDN说队列不是线程安全的:

短版本是,如果希望队列正常工作,必须同步对其的访问。计数/出列中存在明显的线程争用,但更重要的是,不保证任何操作-内部状态可以合法地执行任何操作,并且可能被破坏

您还需要一种最终退出线程的方法


要编写阻塞队列,请参见此处:。

因为您要显式创建一个单独的线程来修改队列,所以无论从哪个线程调用Add(),调用Add()都是不安全的


您需要锁定()if语句块,因为调用q.Count甚至都不安全,然后在Add()方法中再次锁定。

我一开始是这么想的,但队列被释放的唯一位置是在一个循环中。。。因此,Example类外部的任何东西都应该只能对事物进行排队,而不能看到队列。每个调用Example的线程都会分叉一个进入该循环的新线程。若我将10个线程发送到示例中,那个么将有10个线程在那个循环中运行。那些线永远不会回来。因此,随着时间的推移,它会不断累积,你会有一个竞争条件。它们不是静态类,所以它们都是独立的对象,构造函数是创建线程的工具,所以每个对象总是有一个线程。我不相信这会是安全的,因为队列随时可能调整其内部数组的大小。我同意,我相信排队可能会有问题,因为您可以尝试在某个项目完全排队之前将其出列,或者将两个项目写入内部数组中的同一位置。请注意,该场景中的“读取器”是foreach,而不是dequeue(即“写入”)。像这样的实际上,更简单的说法是队列不支持多个呼叫者。是的,但是为什么呢?马克,我知道你比我聪明得多,但是如果你想得到这些分数,你需要告诉我明显的比赛条件是什么我同意你关于内部状态的看法,但是种族条件呢?好的,在这种情况下,种族条件可能并不重要;不会有多个阅读器。然而,线程是很难的:要确定没有竞争条件(没有锁),我需要阅读代码并理解调用模式。为什么不通过锁定计数/出列来表明不存在竞争的可能性?这也意味着,当您以后扩展类时,您不必进行bug搜索。
lock(lockObject)
{
  //do stuff
}