【发布时间】:2021-09-02 01:08:42
【问题描述】:
我有一个队列包装类,它将项目存储到一个列表中,主程序中的多个线程正在使用这些项目,直到列表为空。此时,线程必须等待,直到缓冲区将更多项目排入列表。
每当一个项目入队时,我都会触发一个事件,我需要通知线程他们有新的项目可供使用。
public event EventHandler ItemEnqueued;
public void Enqueue(string item)
{
_itemsList.Add(item);
OnItemEnqueued();
}
void OnItemEnqueued()
{
ItemEnqueued?.Invoke(this, EventArgs.Empty);
}
如何通知主程序的线程一个项目已入队?
非常感谢!
编辑澄清
public class Queue
{
private readonly List<string> _itemsList = new List<string>();
public void Enqueue(String val)
{
_itemsList.Add(val);
OnItemEnqueued();
}
void OnItemEnqueued()
{
//here I have to tell the threads that a new item has been added
}
public string Dequeue()
{
//FIFO queue
if (_itemsList.Any())
{
var first = _itemsList.First();
_itemsList.RemoveAt(0);
return first;
}
return default(string);
}
public int Count()
{
return _itemsList.Count;
}
}
}
我必须创建两个线程并让它们为排队的项目“战斗”:
class Program
{
readonly object _syncLock = new object();
Queue _q = new Queue();
static void Main(string[] args)
{
Program p = new Program();
p.InitThreads();
}
public void InitThreads()
{
lock (_syncLock) //exclusively add items
{
for (var i = 0; i <= 99; i++)
{
_q.Enqueue(i.ToString());
}
}
Thread t1 = new Thread(() => {
while(_q.Count() > 0)
Console.WriteLine("T1 dequeued " + Consume());
});
Thread t2 = new Thread(() =>
{
while (_q.Count() > 0)
Console.WriteLine("T2 dequeued " + Consume());
});
t1.Start();
t2.Start();
//at some moment I have to tell the threads to wait until a new item has been enqueued
}
public string Consume()
{
lock (_syncLock) //safely get one item
{
return _q.Dequeue();
}
}
}
【问题讨论】:
-
听起来您最好使用
BlockingCollection<T>并让您的线程使用GetConsumingEnumerable()进行迭代 -
甚至还有 Channels、DataFlow、Rx 或许多其他东西。简而言之,这个问题已经解决了很多次,您可能会节省一些时间并找到更好的开箱即用解决方案
-
重点是我必须以这种特定的方式解决它,它是练习语句......否则我会寻找另一个解决方案。
-
那么解决方案将比仅仅向线程发出新项目已添加的信号更复杂 - 您还需要确保一次只有一个线程试图使项目出队。但是,您可以使用
ManualResetEvent或AutoResetEvent来表示已添加项目(取决于您希望所有线程还是仅一个线程继续)。然后,您的线程在执行任何操作之前等待发出信号的事件。需要更多的脚手架,但是您的问题有点含糊,无法发布明确的答案... -
我尝试使用 ManualResetEvent 或 AutoResetEvent 但我不知道如何,我已经阅读了很多页面和教程都没有成功。在主程序中,我确实锁定了实例,只让一个线程从队列中消费。但是一旦完成,我不知道如何对不同的线程说:嘿,新物品可用,争取获得它们。我可以从主程序 job.OnItemEnqueued 中看到,但我不知道如何将其链接到线程以使其唤醒。
标签: c# multithreading