7 Replies - 1111 Views - Last Post: 21 February 2014 - 10:03 PM Rate Topic: -----

#1 Rhino1111   User is offline

  • D.I.C Regular
  • member icon

Reputation: 107
  • View blog
  • Posts: 259
  • Joined: 28-August 13

Why doesn't this infinite loop?

Posted 19 February 2014 - 06:15 PM

I was reading through this article -->
http://igoro.com/arc...odel-explained/

Where he states that this program will never exit the while loop.

Quote

This program never terminates (in a release build):


class Test
{
    private bool _loop = true;

    public static void Main()
    {
        Test test1 = new Test();

        // Set _loop to false on another thread
        new Thread(() => { test1._loop = false;}).Start();

        // Poll the _loop field until it is set to false
        while (test1._loop == true) ;

        // The loop above will never terminate!
    }
}



Quote

The full story is that the assembly code emitted by the JIT compiler will store the value test1._loop in the EAX register. The loop condition will keep polling the register, and will read test1._loop from memory again. Even when the thread is pre-empted, the CPU registers get saved. Once the thread is again scheduled to run, the same stale EAX register value will be restored, and the loop never terminates.


But when I compile and run this (optimizations turned on, release build). It doesn't infinite loop as described. Instead it runs one iteration and then receives a fresh read on the second iteration(which then terminates the program).

One of the comments on the article(by the author) states that,

Quote

Great question. The semantics in x86 / x64 are pretty close to all writes going to main memory and all reads coming from main memory...


Which would explain why this program doesn't infinite loop on my hardware, since I'm on x64 architecture. But the opening statements have still left me slightly dumbfounded.

So basically, I'm wondering if this program would truly infinite loop on a 32bit system(don't have a 32bit system to test this on), where-as running it on a x64/x86 system kind of protects you from these "stale read" problems, since it circumvents the "stale reads from the local eax register" problem, with it's stronger memory model.

Is This A Good Question/Topic? 1
  • +

Replies To: Why doesn't this infinite loop?

#2 Skydiver   User is online

  • Code herder
  • member icon

Reputation: 6221
  • View blog
  • Posts: 21,472
  • Joined: 05-May 12

Re: Why doesn't this infinite loop?

Posted 20 February 2014 - 12:11 AM

I don't know about you, but this is the generated code for me when I target x86 with optimized code on:
            // Poll the _loop field until it is set to false
            while (test1._loop == true) ;
002026E5  mov         eax,dword ptr [ebp-4]  
002026E8  mov         eax,dword ptr [eax+4]  
002026EB  cmp         byte ptr [eax+4],0  
002026EF  jne         002026E5  



As you can see, the code obviously compares against main memory, and not against EAX as claimed by the article. Perhaps, it's because I'm using VS2013 and the compiler is much smarter now than it was 4 years ago when that article was written.
Was This Post Helpful? 2
  • +
  • -

#3 Rhino1111   User is offline

  • D.I.C Regular
  • member icon

Reputation: 107
  • View blog
  • Posts: 259
  • Joined: 28-August 13

Re: Why doesn't this infinite loop?

Posted 20 February 2014 - 12:47 AM

Yeah you're correct, But I think it has more to do with processor architecture than the compiler being smarter in this area.

Quote

"x86" processors have a stronger memory model than the CLR itself, which is one reason problems such as seeing stale data are relatively hard to demonstrate.)


I think if this code was compiled on native 32 bit, or on a machine with a weaker memory model, that the assembly code would probably show a cmp against the eax register.

Do you happen to have a native 32bit machine you can test this on?
Was This Post Helpful? 0
  • +
  • -

#4 Skydiver   User is online

  • Code herder
  • member icon

Reputation: 6221
  • View blog
  • Posts: 21,472
  • Joined: 05-May 12

Re: Why doesn't this infinite loop?

Posted 20 February 2014 - 06:58 AM

Actually, that'll be the next set of experiments... a VM running 32-bit, and then if that still yields the same results, fire up the old Dell laptop that supposedly catches fire. (Actually, it's safe, it's serial number was not in the recall range, and it's battery is so dead, that it runs better without a battery.) I'm in no rush, though.

The author has an interesting assertion that it's related to x86/x64. I wonder if it's also true for AMD 32-bit vs. 64-bit? (Actually, I have one of those as well, and I'll be trying it out at some point. Unfortunately, I'll have to dual boot that machine to boot to 32-bit to see if that makes a difference.)
Was This Post Helpful? 0
  • +
  • -

#5 Rhino1111   User is offline

  • D.I.C Regular
  • member icon

Reputation: 107
  • View blog
  • Posts: 259
  • Joined: 28-August 13

Re: Why doesn't this infinite loop?

Posted 20 February 2014 - 06:13 PM

Interested in seeing the results whenever you get around to testing it out.
Was This Post Helpful? 0
  • +
  • -

#6 Rhino1111   User is offline

  • D.I.C Regular
  • member icon

Reputation: 107
  • View blog
  • Posts: 259
  • Joined: 28-August 13

Re: Why doesn't this infinite loop?

Posted 21 February 2014 - 07:40 PM

Interesting enough, while testing something else, I managed to create the stale read problem the author was describing.

The assembly generated for the while check.
while (!p.started) { }
00000063  test        eax,eax 
00000065  je          00000063 



The code:

class Program
    {
        int a = 0;
        bool started = false;
        static void Main(string[] args)
        {
            Program p = new Program();
            Thread t = new Thread(() =>
                {
                    p.started = true;
                    for (int i = 0; i < 100000; i++)
                    {
                        p.a = 10;
                    }
                });
            t.Start();

            while (!p.started) { }
            
            for (int i = 0; i < 100000; i++)
            {
                p.a = 5;
            }
            Console.WriteLine(p.a);
            Console.ReadLine();
            
        }
    }




Basically what I was testing, and was wondering if anybody knows the answer to...
the a = 5 and a = 10 inside the loops are guaranteed to be atomic. But what happens when 2 threads are executing that instruction at the exact same time. Thread1 -> assign 10 to a, Thread2 -> assign 5 to a. What kind of behaviour does this exhibit? I haven't been able to find an answer on the subject yet.

From my tests, it seems that it ends up in a race condition, where a can be either 5 or 10, but never a corrupted value. I assume the memory controller actually never allows 2 write operations on the same memory location at once.

This post has been edited by Rhino1111: 21 February 2014 - 07:45 PM

Was This Post Helpful? 0
  • +
  • -

#7 Rhino1111   User is offline

  • D.I.C Regular
  • member icon

Reputation: 107
  • View blog
  • Posts: 259
  • Joined: 28-August 13

Re: Why doesn't this infinite loop?

Posted 21 February 2014 - 07:52 PM

The intial code posted actually also became a eax to eax compare instruction.

What I did was, Under Tools -> Options -> Debugging

Make sure "Enable Just My Code" is UNCHECKED.
Make sure "Supress JIT Optimizations on Module Load" is UNCHECKED.

The optimization of local eax register comparison is then a legal optimization.

This optimization also becomes legal once the VS debugger isn't attached (i,e running it from the Release .exe and not from within VS in release build.)

So unchecking these options is the way to go to see accurate Assembly code after optimizations.

This post has been edited by Rhino1111: 21 February 2014 - 08:33 PM

Was This Post Helpful? 1
  • +
  • -

#8 Skydiver   User is online

  • Code herder
  • member icon

Reputation: 6221
  • View blog
  • Posts: 21,472
  • Joined: 05-May 12

Re: Why doesn't this infinite loop?

Posted 21 February 2014 - 10:03 PM

Thanks for that update!

For those in the peanut gallery, more information about JIT optimization and debugging in MSDN.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1