Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Within a C# instance method, can 'this' ever be null?

I have a situation where very rarely a Queue of Objects is dequeuing a null. The only call to Enqueue is within the class itself:

m_DeltaQueue.Enqueue(this); 

Very rarely, a null is dequeued from this queue in the following code (a static method):

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);     } 

This is the error report that was generated:

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

I'm very confused as to how a null value could be present in this queue.

As I'm writing this, I'm wondering if this could be a failure of thread synchronization; this is a multi threaded application and It's possible the enqueue or dequeue could be happening simultaneously in another thread.

This is currently under .Net 4.0, but it previously occurred in 3.5/2.0

Update:

This is my (hopefully correct) solution to the problem which was made clear though the great answers below as being a synchronization problem.

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

Enqueue:

    lock (_lock)         m_DeltaQueue.Enqueue(this); 

Dequeue:

       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(); 

I'm still trying to get a handle on proper syncronization, so any comments on the correctness of this would be very appreciated. I initially chose to use the queue itself as a syncronization object because it's private, and introduces less clutter into what is already a very large class. Based on John's suggestion I changed this to lock on a new private static object, _lock.

like image 565
Derrick Avatar asked Feb 20 '11 03:02

Derrick


People also ask

Why use #define in C?

The #define creates a macro, which is the association of an identifier or parameterized identifier with a token string. After the macro is defined, the compiler can substitute the token string for each occurrence of the identifier in the source file.

What is || in C programming?

Logical OR operator: || The logical OR operator ( || ) returns the boolean value true if either or both operands is true and returns false otherwise. The operands are implicitly converted to type bool before evaluation, and the result is of type bool .

What are the C keywords?

Keywords are predefined, reserved words used in programming that have special meanings to the compiler. Keywords are part of the syntax and they cannot be used as an identifier.


1 Answers

this can never be null, unless the method was called using a call instruction in hand-written IL.

However, if you use the same Queue instance on multiple threads simultaneously, the queue will become corrupted and lose data.

For example, if two items are added simultaneously to a near-capacity queue, the first item might be added to the array after the second thread resizes it, which will end up copying a null to the resized array and adding the first item to the old array.

You should protect your queues with locks or use .Net 4's ConcurrentQueue<T>.

like image 54
SLaks Avatar answered Oct 04 '22 17:10

SLaks