我有一个FIFO和两个线程。其中一个线程只会对FIFO进行入队操作,而另一个线程只会对FIFO进行出队操作。我需要使用ConcurrentQueue还是普通的Queue就足够了?
我有一个FIFO和两个线程。其中一个线程只会对FIFO进行入队操作,而另一个线程只会对FIFO进行出队操作。我需要使用ConcurrentQueue还是普通的Queue就足够了?
Queue
对象实例提供线程安全和同步。 为了避免重复发明轮子并自己完成操作,建议使用Microsoft的ConcurrentQueue
。如果您使用一个如果需要从多个线程同时访问集合,请使用ConcurrentQueue或ConcurrentStack。
Queue
(即非ConcurrentQueue
)并且有多个线程更新对象实例,则可能会遇到运行时异常,例如:class Program
{
static Queue<string> Queue = new Queue<string>();
static void Main(string[] args)
{
Thread producer = new Thread(Enqueue);
Thread consumer = new Thread(Dequeue);
producer.Start();
consumer.Start();
Console.ReadKey();
}
static void Enqueue()
{
for (int i = 0; i < 10000; i++)
{
Queue.Enqueue("Number : " + i);
SimulateWork();
}
}
static void Dequeue()
{
while (true)
{
if (Queue.Any())
{
Console.WriteLine(Queue.Dequeue());
SimulateWork();
}
}
}
static void SimulateWork()
{
for (int i = 0; i < 1000000; i++)
{ }
}
}
Queue
实例处于不一致状态时会发生什么。即使只有一个生产者和一个消费者,您仍需要适当的同步。如果在Enqueue
和Dequeue
操作周围添加锁定或同步,您会发现它可以正常运行。 lock (lockObject)
{
Queue.Enqueue("Number : " + i);
SimulateWork();
}
lock (lockObject)
{
if (Queue.Any())
{
Console.WriteLine(Queue.Dequeue());
SimulateWork();
}
}
ConcurrentQueue
。
如上所述,如果您有多个线程,您的一些并发集合类型使用轻量级同步机制,例如SpinLock、SpinWait、SemaphoreSlim和CountdownEvent,在.NET Framework 4中是新的。这些同步类型通常在将线程置于真正的等待状态之前进行繁忙自旋。当预计等待时间非常短时,自旋远比等待更少的计算开销,后者涉及昂贵的内核转换。对于使用自旋的集合类,这种效率意味着多个线程可以以非常高的速率添加和删除项目。有关自旋与阻止的更多信息,请参见SpinLock和SpinWait。
Queue
对象实例需要线程安全和同步。为了避免重复造轮子并自己编写代码,我强烈建议使用Microsoft的ConcurrentQueue
。
参考资料:
线程安全集合:
https://learn.microsoft.com/en-us/dotnet/standard/collections/thread-safe/
锁关键字:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement
线程:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/threading/index
简短回答:是的,即使只有一个写线程和一个读线程,您仍需要一个线程安全的解决方案。
使用ConcurrentQueue会更容易。如果您愿意,可以使用Queue,但必须自己进行锁定。