多线程.NET队列问题

| 我的代码中出现一个奇怪的错误。它非常罕见(也许每隔几周发生一次),但是它在那里而且我不确定为什么。 我们有2个线程在运行,有1个线程获取网络消息并将其添加到如下队列中:
DataMessages.Enqueue(new DataMessage(client, msg));
另一个线程将消息从此队列中移出并进行处理,如下所示:
while (NetworkingClient.DataMessages.Count > 0)
{
    DataMessage message = NetworkingClient.DataMessages.Dequeue();

    switch (message.messageType)
    {
       ...
    }
}
但是,每隔一段时间我就会在第2行上得到NullReferenceException,并且在调试器中可以看到该消息为null。 不可能将空值放入队列(请参见代码的第一位),而这是使用队列的仅有的两件事。 Queue是否不是线程安全的,是否可能是我在另一个线程入队的确切时刻出队,这会导致故障?     
已邀请:
        
    while (NetworkingClient.DataMessages.Count > 0)
    {
        // once every two weeks a context switch happens to be here.
        DataMessage message = NetworkingClient.DataMessages.Dequeue();

        switch (message.messageType)
        {
           ...
        }
    }
...并且当您在该位置获得上下文切换时,第一个表达式的结果 (
NetworkingClient.DataMessages.Count > 0
)对于两个线程都是正确的,而执行
Dequeue()
操作的线程首先获取对象,第二个线程获取null(而不是InvalidOperationException,因为Queue的内部状态为\尚未完全更新以引发正确的异常)。 现在,您有两个选择: 使用.NET 4.0 ConcurrentQueue 重构代码: 并使其看起来像这样:
while(true)
{
  DataMessage message = null;

  lock(NetworkingClient.DataMessages.SyncRoot) {
       if(NetworkingClient.DataMessages.Count > 0) {
          message = NetworkingClient.DataMessages.Dequeue();
       } else {
         break;
       }
    }
    // .. rest of your code
}
编辑:更新以反映Heandel的评论。     
           Queue不是线程安全的吗?   我正要出队   另一个线程正在排队,   这会导致故障吗? 究竟。
Queue
不是线程安全的。线程安全队列为
System.Collections.Concurrent.ConcurrentQueue
。改用它可以解决您的问题。     
        如果您对确切原因感兴趣:
Enqueue
看起来像这样:
this._array[this._tail] = item;
this._tail = (this._tail + 1) % this._array.Length;
this._size++;
this._version++;
像这样的
Dequeue
T result = this._array[this._head];
this._array[this._head] = default(T);
this._head = (this._head + 1) % this._array.Length;
this._size--;
this._version++;
比赛是这样的: 队列中有1个元素(head == tail),因此您的阅读器线程开始出队,但在ѭ11中的第一行之后被中断 然后,将另一个元素放入队列,并将其放置在位置
tail
处,该位置等于
head
。 现在,
Dequeue
恢复并用ѭ18inserted覆盖
Enqueue
刚刚插入的元素。 下次调用出队时,将获得默认值(T)(在您的情况下为null),而不是实际值     

要回复问题请先登录注册