Weird thread NullReferenceException while reading a value that exists?

I have an incredibly strange NullReferenceException when reading a value from an open field on an object that I know exists. The main thread is this:

Edit: I realized that I forgot to mention something important, it does not happen every time I try to read the Tag value, but only enough time that I can play it every time just by running the code, but not immediately, when the code works

  • The server receives the message (worker thread)
  • The connection that sent the get message is established as the Tag field in the message object (workflow)
  • The message is sent to the ReceivedMessages queue (a regular Queue that is protected by locks for serialized access) (workflow)
  • Message is being read (Main topic)
  • I try to read the Tag field of a message to get a connection, it sometimes returns null and throws an exception, but when the exception gets thrown and I check the Message object, I see the Connection object (which is the object that is in the Tag field), it is clear as day ( Main stream)

If you look at this image, you will see it as a day:

Weird thread behavior

You can see where I am marked with a green field, I try to read the message.Tag property in three different ways: they all return null, as you can see in the part marked with a blue field.

However, if you look at two areas marked as red, you can see how the day the object really exists. And to eliminate any confusion, the part into which the message falls into the queue of received messages is as follows:

I, as you can see, I even tried to do Thread.VolatileWrite to make sure the value is written

 message.Tag = buffer.Tag; Thread.VolatileWrite(ref message.Tag, buffer.Tag); if (message.Tag == null) { isNullLog.Add(message.Id); } // Queue into received messages lock (peer.ReceivedMessages) { peer.ReceivedMessages.Enqueue(message); } 

The snippet above happens in the workflow, and as you can see, I copy buffer.Tag to message.Tag , I even set up a small runtime check for debugging, which checks message.Tag for a value of zero and add it to a list called " isNullLog "if so. When a NullReferenceException hits the main thread, this list is empty.

You also see that I am blocking the peer.ReceivedMessages and pushing the message into the queue after I set the message.Tag field.

Additionally, to be even clearer, this is a function that is used to read a message from the peer.ReceivedMessages queue:

 public bool TryGetMessage(out TIncomingMessage message) { lock (ReceivedMessages) { if (ReceivedMessages.Count > 0) { message = ReceivedMessages.Dequeue(); return true; } } ReceivedMessageEvent.Reset(); message = null; return false; } 

You can see that I am blocking the queue even before I check the quantity, and if it is not empty, I set the out property and return true, otherwise I return false.

Honestly, I’m completely at a dead end, I wrote several multithreaded applications and never came across this.

A bit updated, I also tried marking the Tag field as volatile , making it look like this public volatile object Tag; but that doesn't seem to help.

+6
source share
1 answer

I really fixed it right now, as always when working with streams you need to be very careful when reading / writing values. I forgot to clear the local variable message in the receive loop and ended up "reusing" the same message in the next iteration of the loop because it has an if(message == null) { /* create new message */ } check before each iteration and when I don't cleared this reading the thread ended up trampling the entire "old" message that was stored here when trying to write a new message to it!

+2
source

Source: https://habr.com/ru/post/902481/


All Articles