Multithreaded .NET queue problems(多线程 .NET 队列问题)
问题描述
我的代码中有一个奇怪的错误.这是极其罕见的(可能每隔几周发生一次),但它就在那里,我不知道为什么.
I'm have a wierd error in my code. It's extremely rare (happens once every few weeks maybe), but it's there and I'm not sure why.
我们有 2 个线程在运行,1 个线程获取网络消息并将它们添加到队列中,如下所示:
We have 2 threads running, 1 thread gets networked messages and adds them to a Queue like this:
DataMessages.Enqueue(new DataMessage(client, msg));
另一个线程从这个队列中取出消息并处理它们,如下所示:
Another thread takes messages off this queue and handles them, like this:
while (NetworkingClient.DataMessages.Count > 0)
{
    DataMessage message = NetworkingClient.DataMessages.Dequeue();
    switch (message.messageType)
    {
       ...
    }
}
但是,我经常在 switch (message.messageType) 行上收到 NullReferenceException,我可以在调试器中看到该消息为空.
However once every so often I get a NullReferenceException on the line switch (message.messageType) and I can see in the debugger that message is null.
不可能将空值放入队列(参见代码的第一部分),这是唯一使用队列的两件事.
It is not possible that a null value was put onto the queue (see the first bit of code), and these are the only 2 things that use the queue.
队列不是线程安全的吗,是不是我在另一个线程入队的确切时刻出队,这导致了故障?
Is Queue not thread-safe, could it be that I'm dequeuing at the exact moment that the other thread is enqueuing and this causes the glitch?
推荐答案
    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,因为队列的内部状态没有完全更新以抛出正确的异常).
... and when you get that context switch in that location, the result of the first expression
(NetworkingClient.DataMessages.Count > 0) is true for both threads, and the one that get's to the Dequeue() operation first get's the object and the second thread get's a null (instead of InvalidOperationException because the Queue's internal state wasn't fully updated to throw the right exception).
现在你有两个选择:
使用 .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 的评论.
updated to reflect Heandel's comment.
这篇关于多线程 .NET 队列问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:多线程 .NET 队列问题
				
        
 
            
        - C#MongoDB使用Builders查找派生对象 2022-09-04
 - 良好实践:如何重用 .csproj 和 .sln 文件来为 CI 创建 2022-01-01
 - Web Api 中的 Swagger .netcore 3.1,使用 swagger UI 设置日期时间格式 2022-01-01
 - 带有服务/守护程序应用程序的 Microsoft Graph CSharp SDK 和 OneDrive for Business - 配额方面返回 null 2022-01-01
 - 如何用自己压缩一个 IEnumerable 2022-01-01
 - C# 中多线程网络服务器的模式 2022-01-01
 - 在哪里可以找到使用中的C#/XML文档注释的好例子? 2022-01-01
 - WebMatrix WebSecurity PasswordSalt 2022-01-01
 - MoreLinq maxBy vs LINQ max + where 2022-01-01
 - 输入按键事件处理程序 2022-01-01
 
						
						
						
						
						
				
				
				
				