use*_*458 13 c# queue multithreading
我使用下面的代码来实现和测试阻塞队列.我通过启动5个并发线程(删除程序)来测试队列,以便将项目从队列中拉出来,阻塞队列是否为空,以及1个并发线程(加法器)将项目间接添加到队列中.但是,如果我让它运行的时间足够长,我会得到一个异常,因为即使队列为空,其中一个卸载线程也会处于等待状态.
有谁知道为什么我得到例外?请注意,我很想知道为什么这不起作用而不是工作解决方案(就像我可以谷歌那样).
我非常感谢你的帮助.
using System;
using System.Threading;
using System.Collections.Generic;
namespace Code
{
class Queue<T>
{
private List<T> q = new List<T>();
public void Add(T item)
{
lock (q)
{
q.Add(item);
if (q.Count == 1)
{
Monitor.Pulse(q);
}
}
}
public T Remove()
{
lock (q)
{
if (q.Count == 0)
{
Monitor.Wait(q);
}
T item = q[q.Count - 1];
q.RemoveAt(q.Count - 1);
return item;
}
}
}
class Program
{
static Random r = new Random();
static Queue<int> q = new Queue<int>();
static int count = 1;
static void Adder()
{
while (true)
{
Thread.Sleep(1000 * ((r.Next() % 5) + 1));
Console.WriteLine("Will try to add");
q.Add(count++);
}
}
static void Remover()
{
while (true)
{
Thread.Sleep(1000 * ((r.Next() % 5) + 1));
Console.WriteLine("Will try to remove");
int item = q.Remove();
Console.WriteLine("Removed " + item);
}
}
static void Main(string[] args)
{
Console.WriteLine("Test");
for (int i = 0; i < 5; i++)
{
Thread remover = new Thread(Remover);
remover.Start();
}
Thread adder = new Thread(Adder);
adder.Start();
}
}
}
Run Code Online (Sandbox Code Playgroud)
Eri*_*ert 17
如果我让它运行的时间足够长,我会得到一个例外,因为即使队列为空,其中一个卸载线程也会处于等待状态.有谁知道为什么我得到例外?
问题很奇怪,因为显然你知道答案:你的第一句话回答了第二句所提出的问题.您得到异常是因为当队列为空时,卸载线程退出等待状态.
要解决这个问题,你需要使用循环而不是"if".正确的代码是:
while(q.Count == 0) Monitor.Wait(q);
Run Code Online (Sandbox Code Playgroud)
不
if(q.Count == 0) Monitor.Wait(q);
Run Code Online (Sandbox Code Playgroud)
一位意见提供者指出,或许你的问题是"在什么情况下消费者线程可以在队列为空时获得监视器?"
嗯,你比我们更能回答这个问题,因为你是运行程序并查看输出的人.但就在我的脑海中,这是一种可能发生的方式:
现在,线程1在监视器中有一个空队列.
一般来说,在推理这些问题时,你应该把"脉冲"看作是一只带有附注的鸽子.一旦被释放,它与发送者没有任何联系,如果它找不到它的家,它就会在荒野中消失,其消息未被传递.你知道什么时候Pulse就是如果有任何线程在等待,那么一个线程将来会在某个时候进入就绪状态; 你不知道关于线程操作的相对时间的任何其他信息.