Unit test passes in debug build but fails in release build

c#, multithreading, unit-testing

Solution

The flag `IsSomethingDone` is being cached in a CPU register, and never reloaded from memory, so that when one thread modifies it, the other never sees the modified value. This is an optimization which the .NET JIT compiler does, so you'd need to look at the actual x86/x64 binary dissasembly to see this, MSIL is not deep enough :-)

The solution is to mark your flag as `volatile`

This is a textbook example of one of the kind of multithreading bugs that can occur. So much so, that here's a link to part of a presentation I did at TechEd New Zealand 2012 on this exact subject. Hopefully it should explain what's going on in more detail

http://orionedwards.blogspot.co.nz/2012/09/teched-2012-background-2-compiler.html

As you have mentioned, you can't put `volatile` on a local variable, but you should be able to use `Thread.VolatileRead` instead.

I'd suggest not using this design at all - your main thread is going to spin using 100% CPU until your worker completes, which is horrible. A better solution is to use a `ManualResetEvent` (or other kind of signaling mechanism).

Here's an example

public void DoingSomethingTest()
{
    var done = new ManualResetEvent(false); // initially not set

    //Setup
    //Doing some setup here.
    target.SomethingDone += (sender, args) =>
        {
            done.Set();
        };

    //Exercise
    target.DoSomething(_someParameter);
    done.WaitOne(); // waits until Set is called. You can specify an optional timeout too which is nice

    //Verify
    //Doing some asserts here.
}

Problem

I have written a unit test for an asynchronous class member. The test passes as expected when I execute my test under "Debug build". However, it hangs the CPU (while loop is deadlocked) when I execute my test under "Release build". If I specifically configure the Unit test project with Debug build (that is Debug build unit test assembly and Release build target assembly), the test passes as well. Code to Test ``` public override void DoSomething(object parameter) { ThreadPool.QueueUserWorkItem(AsyncDoSomething, parameter); } private void AsyncDoSomething(object parameter) { //Doing something ..... //Something is done RaiseSomethingIsDone(); } ``` My Unit Test ``` public void DoingSomethingTest() { bool IsSomethingDone = false; //Setup //Doing some setup here. target.SomethingDone += (sender, args) => { IsSomethingDone = true; }; //Exercise target.DoSomething(_someParameter); while (!IsSomethingDone ){} //Verify //Doing some asserts here. } ``` Here is the IL generated by the C# compiler under Debug configuration and Release configuration: Debug while loop IL interpenetration: ``` IL_00cb: ldloc.s 'CS$<>8__locals7' IL_00cd: ldfld bool IsSomethingDone IL_00d2: ldc.i4.0 IL_00d3: ceq IL_00d5: stloc.s CS$4$0001 IL_00d7: ldloc.s CS$4$0001 IL_00d9: brtrue.s IL_00c9 ``` Release while loop IL interpenetration: ``` IL_00bc: ldloc.s 'CS$<>8__locals7' IL_00be: ldfld bool IsSomethingDone IL_00c3: brfalse.s IL_00bc ``` I understand there are better ways to synchronize the test thread to the background ThreadPool thread. My questions are why is the release build not working? The flag IsSomethingDone is not set by the worker thread. Is it because the eventhandler (the lambda expression) does not get executed? Is the event not raised correctly? By the way, I verified that DoSomething is executed correctly and generated the correct result. Follow up Questions: Should one build unit test projects under Debug Build or Release Build ? Should one test the target assembly under Debug Build or Release Build ?

Original source