0

I am getting a null reference exception that comes from this code in a multi-threaded environment:

public static void GetLogger(string loggerName) {

    Logger logger = ListOfLoggers.Find(delegate(Logger newLogger) 
    { 
        return newLogger.Name.Contains(loggerName); 
    });

    if (logger == null) {
        ListOfLoggers.Add(new Logger(loggerName));
    }
}

In the code above:

  • ListOfLoggers can be empty, but is never null as it is initialized as a static readonly variable.

  • A null Logger object cannot be created (will cause a TypeInitializationException), so ListOfLoggers never contains a null Logger object.

  • The only way to instantiate a Logger object is to provide an argument that gets set to the Logger object's Name property, so I also do not see how newLogger.Name can be null.

The faulting line of the stack trace is:

LogManager.<>c__DisplayClass1.<GetLogger>b__0(Logger newLogger) 

and seems to suggest that the class generated by the compiler to hold the newLogger local variable in the delegate closure is the one that throws the null reference exception.

This seems to only happen in a multi-threaded environment, and I never see the null reference when calling the code above with a single thread. How is this possible?

Kevin Lee
  • 67
  • 6
  • Can you debug the code in visual studio? If so, can you see which variable/property is null? – Yacoub Massad Jan 28 '16 at 23:33
  • Use a debugger, with stop on exception activated (in VS with standard shortcuts, CTRL+ALT+E and tick 'Thrown' on 'Common Language Runtime Exeption'), and inspect variables. One of your assumption is probably false, and you should be able to see it by debugging. Or at least you will see the other cause if there is one. – Frédéric Jan 28 '16 at 23:34
  • I bet either `newLogger` or `newLogger.Name` is `null` - just debug it. – Lucas Trzesniewski Jan 28 '16 at 23:34
  • This turned out to be a classic race condition resulting in the newLogger variable to sometimes be read as null. The static readonly variable ListOfLoggers was being modified across multiple threads. When a modification was made in one thread, compiler/CPU/CLR optimizations meant that other threads wouldn't necessarily see the modification, and would read the newly added property as a null object. This article helped a lot with debugging and I'll leave it here in case it helps someone else: [link](http://www.albahari.com/threading/part4.aspx) – Kevin Lee Feb 05 '16 at 01:34

0 Answers0