c# - 在 C# 实例方法中, 'this' 可以为空吗?

标签 c# .net multithreading thread-safety

我有一种情况,对象队列很少使空值出队。对 Enqueue 的唯一调用是在类本身中:

m_DeltaQueue.Enqueue(this);

在极少数情况下,在以下代码(静态方法)中 null 从该队列中出队:

while (m_DeltaQueue.Count > 0 && index++ < count)
    if ((m = m_DeltaQueue.Dequeue()) != null)
        m.ProcessDelta();
    else if (nullcount++ < 10)
    {
        Core.InvokeBroadcastEvent(AccessLevel.GameMaster, "A Rougue null exception was caught, m_DeltaQueue.Dequeue of a null occurred. Please inform an developer.");
        Console.WriteLine("m_DeltaQueue.Dequeue of a null occurred: m_DeltaQueue is not null. m_DeltaQueue.count:{0}", m_DeltaQueue.Count);
    }

这是生成的错误报告:

[Jan 23 01:53:13]: m_DeltaQueue.Dequeue of a null occurred: m_DeltaQueue is not null. m_DeltaQueue.count:345

我很困惑为什么空值会出现在这个队列中。

在我写这篇文章的时候,我想知道这是否可能是线程同步失败;这是一个多线程应用程序,入队或出队可能在另一个线程中同时发生。

目前在.Net 4.0下,但之前出现在3.5/2.0

更新:

这是我(希望是正确的)解决问题的方法,尽管下面的很好的答案已经清楚地表明这是一个同步问题。

private static object _lock = new object();
private static Queue<Mobile> m_DeltaQueue = new Queue<Mobile>();

排队:

    lock (_lock)
        m_DeltaQueue.Enqueue(this);

出队:

       int count = m_DeltaQueue.Count;
       int index = 0;
       if (m_DeltaQueue.Count > 0 && index < count)
           lock (_lock)
               while (m_DeltaQueue.Count > 0 && index++ < count)
                   m_DeltaQueue.Dequeue().ProcessDelta();

我仍在尝试处理正确的同步,因此非常感谢任何对此正确性的评论。我最初选择使用队列本身作为一个同步对象,因为它是私有(private)的,并且在已经非常大的类中引入了更少的困惑。根据 John 的建议,我将其更改为锁定一个新的私有(private)静态对象 _lock。

最佳答案

this永远不能为空,除非该方法是使用 call 调用的手写 IL 指令。

但是,如果您使用相同的 Queue同时在多个线程上实例,队列将损坏并丢失数据。

例如,如果同时将两个项目添加到接近容量的队列中,则第一个项目可能会在第二个线程调整其大小后添加到数组中,这将最终复制一个 null。到调整大小的数组并将第一项添加到旧数组。

您应该使用锁或使用 .Net 4 的 ConcurrentQueue<T> 来保护您的队列.

关于c# - 在 C# 实例方法中, 'this' 可以为空吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5055068/

相关文章:

c# - jQuery DateTimePicker : Post datetime data to ViewModel in MVC3 action using jQuery $. 后()

c# - 固定和不安全有什么区别

c# - OpenSSL无法验证ECDSA签名C++、C#验证正确

c# - 如何从 Expression<Action<T>> 获取接口(interface)成员名称

c# - 动态合并 2 个类

c++ - for循环中的多线程错误

c# - Global.asax 中的多个 AutoMapper.Configure()

c# - 软键盘重叠控件(WPF、桌面)

Java:捕获异常是异步的吗?

连接到 Redis 时永远不会终止的 Objective-C 控制台应用程序