队列.Dequeue 返回 null
我有一个场景,其中
多个线程正在向队列推送数据
只有一个线程正在使用下面的代码处理数据
-
while ( Continue )
{
while ( queue.Count > 0 )
{
MyObj o = queue.Dequeue();
someProcess(o);
}
myAutoResetEvent.WaitOne();
}
但有时,queue.Dequeue() 在上面的场景中返回 null 什么给出?
I have a scenario where
multiple threads are pushing data on a Queue
only ONE thread is processing data using code below
code -
while ( Continue )
{
while ( queue.Count > 0 )
{
MyObj o = queue.Dequeue();
someProcess(o);
}
myAutoResetEvent.WaitOne();
}
But sometimes, queue.Dequeue() returns null in the scenario above
What gives ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您需要阅读此内容博客文章。
另外,这是用于线程之间通信的“通道”的一个非常小的框架:
You need to read this blog post.
Also, here's a very minimal skeleton of a "channel" for communication between threads:
您需要同步对队列的访问。将
lock
语句放在访问队列(读取和写入)的所有代码部分周围。如果您从多个线程同时访问队列,则内部结构可能会被损坏,并且几乎任何事情都可能发生。You need to synchronise the access to the queue. Put
lock
statements around all code sections that access the queue (both reading and writing). If you access the queue simultaneously from multiple threads the internal structures may be corrupted and just about anything can happen.你说:
Queue.Enqueue
方法不是线程安全的。这意味着工作是在 Enqueue 方法内完成的,如果多个线程调用该方法,则需要同步该方法。一个简单的示例是更新Count
属性。可以肯定的是,Enqueue
方法中的某处有一行看起来像这样的内容:但众所周知,这不是一个原子操作。实际上更像是这样的(就实际发生的情况而言):
假设
count
当前为 5,并且线程 1 超过了int newCount = count + 1
...然后线程 1 会想:“好吧,现在计数是 5,所以我将其设为 6。”但执行的下一个操作是线程 2 到达 int newCount = count + 1 并思考与线程 1 相同的事情(“计数现在为 6”)。因此,刚刚将两个项目添加到队列中,但计数仅从 5 增加到 6。这只是一个非常基本的示例,说明像
Queue.Enqueue
这样的非线程安全方法是如何工作的当访问不同步时可能会变得混乱。它没有具体解释你的问题中发生了什么;我的目的只是指出您所做的事情不是线程安全的,并且会导致意外行为。You say:
The
Queue<T>.Enqueue
method is not thread-safe. This means that work gets done within theEnqueue
method that needs to be synchronized if multiple threads are calling it. A simple example would be updating theCount
property. It's a safe bet that somewhere in theEnqueue
method there's a line that looks something like this:But as we all know, this isn't an atomic operation. It's really more like this (in terms of what's actually happening):
So say the
count
is currently 5, and Thread 1 gets pastint newCount = count + 1
... then Thread 1 thinks, "OK, the count is now 5, so I'll make it 6." But the very next operation that gets executed is where Thread 2 gets toint newCount = count + 1
and thinks the same thing as Thread 1 ("the count is now 6"). So two items have just been added to the queue, but the count only went from 5 to 6.This is just a very basic example of how a non thread-safe method like
Queue<T>.Enqueue
can get messed up when access is not synchronized. It doesn't specifically explain what's happening in your question; my intention is simply to point out that what you're doing is not thread-safe and will cause unexpected behavior.Guffa 是正确的,有多个线程读取和写入队列会导致问题,因为 Queue不是线程安全的。
如果您使用的是 .NET 4,请使用 ConcurrentQueue 类,它是线程安全的。如果您不是使用 .NET 3 或更早版本,您可以自己进行锁定(正如 Guffa 指出的那样),也可以使用第 3 方库。
Guffa is correct, having multiple threads reading and writing to the queue will cause problems, because Queue<T> is not thread safe.
If you're on .NET 4, use the ConcurrentQueue<T> class, which is thread safe. If you're not on .NET 3 or earlier, you can either do your own locking, as Guffa pointed out, or use a 3rd party library.
确保没有任何东西将
null
值推入队列。允许null
作为排队值。另外,根据此文档,只有Queue;
的静态成员是线程安全的,所以要小心跨线程的读写。Make sure nothing's pushing
null
values into the queue.null
s are allowed as queued values. Also, according to this document, onlyQueue<T>
's static members are thread-safe, so beware of doing reading and writing across threads.为什么不这样解决问题呢?
更新
好吧,在阅读了 Earwickers 的评论和所有其他答案后,你是对的,我只是错了。因此请不要在多线程上下文中使用上面的代码。
Why don't you solve the problem that way?
Update
Ok, after reading Earwickers comment and all the other answers, you are all right and i'm just false. So please don't use the code above in multithreaded contexts .
如果您碰巧使用非通用队列(不是我建议使用它),您可以使用 Queue.Synchronized 方法来获取线程安全包装器:
否则您应该像其他人建议的那样自行锁定。
If you happen to be using non-generic Queue (not that I advise to use it), you can use Queue.Synchronized method to get a thread-safe wrapper:
Otherwise you should take care of locking yourself, as others suggest.