gpt4 book ai didi

c# - 在 C# 中实现阻塞队列

转载 作者:可可西里 更新时间:2023-11-01 08:06:16 24 4
gpt4 key购买 nike

我使用下面的代码来实现和测试阻塞队列。我通过启动 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();
}
}
}

最佳答案

if I leave it running for long enough I get an exception because one of the remover threads comes out of a waiting state even when the queue is empty. Does anyone know why I get the exception?

这个问题很奇怪,因为您显然知道答案:您的第一句话回答了第二句话提出的问题。 您得到异常是因为当队列为空时移除线程退出等待状态。

要解决此问题,您需要使用循环而不是“if”。正确的代码是:

while(q.Count == 0) Monitor.Wait(q);

不是

if(q.Count == 0) Monitor.Wait(q);

更新:

有评论者指出,您的问题可能是“队列为空时,消费者线程在什么情况下可以获得监视器?”

嗯,您比我们更有能力回答这个问题,因为您是运行程序并查看输出的人。但就在我的脑海中,这是一种可能发生的方式:

  • 消费者线程 1:WAITING
  • 消费者线程 2:准备就绪
  • 生产者线程 3:拥有监视器
  • 队列中只有一个元素。
  • 线程 3 个脉冲。
  • 线程 1 进入就绪状态。
  • 线程 3 放弃监视器。
  • 线程 2 进入监视器。
  • 线程 2 消费队列中的项目
  • 线程 2 放弃监视器。
  • 线程 1 进入监视器。

现在线程 1 在监视器中,队列为空。

一般来说,在推理这类问题时,您应该将“Pulse”想象成一只附有便条的鸽子。一旦被释放,它就与发件人没有联系,如果找不到它的家,它就会死在荒野中,而它的信息也没有送达。当你使用 Pulse 时,你所知道的是,如果有任何线程在等待,那么一个线程将在未来的某个时间进入就绪状态;您对线程操作的相对时间一无所知。

关于c# - 在 C# 中实现阻塞队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9422133/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com