none
Memory barrier, reorder RRS feed

  • Question

  • Hi, there,

    I can easily create the demo with the belows to illustrate the usgae of volalite, memory barrier, all those fences.

    public class Program
     {
      int a;
      int b;
      public static void Main(string[] args)
      {
       Program very = new Program();

       new Thread(delegate()
         {
          Thread.Sleep(500);
          very.a = 1;
          very.b = 1;
          Console.WriteLine("T1 {0}, {1}", very.a, very.b);
         }).Start();

       while (very.a != 1 || very.b != 1)
       {
        //Console.WriteLine("{0}, {1}", very.a, very.b);
       }

       Console.WriteLine("OK {0}, {1}", very.a, very.b);
       Console.ReadLine();
      }
     }

    My question, why i cannot see the blocking after i changed the code likes, or just comment out //Console.WriteLine("{0}, {1}", very.a, very.b) in above:

    public class Program
     {
      int a;
      int b;

      public static void Main(string[] args)
      {
       Program very = new Program();

       new Thread(delegate()
         {
          Thread.Sleep(500);
          very.a = 1;
          very.b = 1;
          Console.WriteLine("T1 {0}, {1}", very.a, very.b);
         }).Start();

       // Change || to &&, non-blocking,seems the up-to-date values is there.

       while (very.a != 1 && very.b != 1)
       {
           // Console.WriteLine("{0}, {1}", very.a, very.b);
       }

       Console.WriteLine("OK {0}, {1}", very.a, very.b);
       Console.ReadLine();
      }
     }

    is there any implicit memory barrier there? please help.


    TransactionFlow

    Thursday, June 28, 2012 6:23 AM

Answers

  • Hi, Feng,

    Thanks again.

    I think i had gotten something to explain the different observations:

    In the case of  blocking (OK 1, 1 was not displayed ),  the value of very.a was read from the register, like EAX,  not the value already updated by the other thread , maybe compiler had optimized the code to just read the value qulickly from register,  to eliminate the blocking, we need to declare the a as volatile to prohibat the optimization.

    In other normal cases, the complier do the "right" thing: read the reference of very from register, add the offset to read the variable again, so the most recent value was caught

    Anyway, thanks again for the help.


    SAY NEVER

    Wednesday, July 4, 2012 5:22 AM

All replies

  • Hi, there,

    I can easily create the demo with the belows to illustrate the usgae of volalite, memory barrier, all those fences.

    public class Program
     {
      int a;
      int b;
      public static void Main(string[] args)
      {
       Program very = new Program();

       new Thread(delegate()
         {
          Thread.Sleep(500);
          very.a = 1;
          very.b = 1;
          Console.WriteLine("T1 {0}, {1}", very.a, very.b);
         }).Start();

       while (very.a != 1 || very.b != 1)
       {
        //Console.WriteLine("{0}, {1}", very.a, very.b);
       }

       Console.WriteLine("OK {0}, {1}", very.a, very.b);
       Console.ReadLine();
      }
     }

    My question, why i cannot see the blocking after i changed the code likes, or just comment out //Console.WriteLine("{0}, {1}", very.a, very.b) in above:

    public class Program
     {
      int a;
      int b;

      public static void Main(string[] args)
      {
       Program very = new Program();

       new Thread(delegate()
         {
          Thread.Sleep(500);
          very.a = 1;
          very.b = 1;
          Console.WriteLine("T1 {0}, {1}", very.a, very.b);
         }).Start();

       // Change || to &&, non-blocking,seems the up-to-date values is there.

       while (very.a != 1 && very.b != 1)
       {
           // Console.WriteLine("{0}, {1}", very.a, very.b);
       }

       Console.WriteLine("OK {0}, {1}", very.a, very.b);
       Console.ReadLine();
      }
     }

    is there any implicit memory barrier there? please help.


    TransactionFlow

    This is a little hard to follow - I dont have time to run the code - can you tell us what you see and what you'd expect to see?

    The code also contains no barrier directives/instructions from what I can see.

    None are declared "volatile" nor are you using Volatile.Read or Volatile.Write or inserting reorder fences explicitly, so there is nothing to restrict possible reorderings.

    Cap'n

    Thursday, June 28, 2012 1:10 PM
  • Hi, Cap'n,

    Thanks for the reply.

    My obersvation:

    Run #1, I only see T1 {0}, {1}",  but not "OK {0}, {1}".  Since we haven't used any fence,   (very.a != 1 && very.b != 1) is always true, and it keeps running, blocking the thread.

    Run #2, I can see T1 {0}, {1}" and "OK {0}, {1}".  From what i undestand, no fence here as well, we should not see "OK {0}, {1}", but why the main thread can see the latest changes and there is no blocking.

    The most strange thing to me is, after i comment out the line: Console.WriteLine("{0}, {1}", very.a, very.b) inside the while, i can see "OK {0}, {1}". because console.writeline is an expensive operation, after some loops, the value are finally flushed?

    Thanks again


    SAY NEVER

    Friday, June 29, 2012 1:33 AM
  • Hi XianZhong,

    Welcome to the MSDN Forum.

    I have test your code with the following cases:

    1. 

                while (very.a != 1 || very.b != 1)
                {
                    Console.WriteLine("{0}, {1}", very.a, very.b);
                }

    2.

                while (very.a != 1 && very.b != 1)
                {
                    Console.WriteLine("{0}, {1}", very.a, very.b);
                }

    3. 

                while (very.a != 1 && very.b != 1)
                {
                    //Console.WriteLine("{0}, {1}", very.a, very.b);
                }

    4.

                while (very.a != 1 || very.b != 1)
                {
                    //Console.WriteLine("{0}, {1}", very.a, very.b);
                }

    I always see  both OK 1, 1 and  T1 1, 1.

    And this is an expected result.

    So what do you mean " I only see T1 {0}, {1}",  but not "OK {0}, {1}"."? And "but why the main thread can see the latest changes and there is no blocking."?

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, June 29, 2012 2:27 PM
    Moderator
  • Hi, Feng

    Thanks very much for the answer.

    My Env:  Release mode, X86, XP system, Intel(R) Core(TM) 2 Duo CPU E8400 @3.00 GHz

    Run #4

    •  while (very.a != 1 || very.b != 1)
                  {
                      //Console.WriteLine("{0}, {1}", very.a, very.b);
                  }

    Seems the while never has the chance to be false, and keep looping there, it's the blocking, i cannot see the OK 1, 1. To me, I can explain to myself that the writing of very.a has not been flushed; we need to put some fences to see the latest updates.

    But what is odd to me is:

    Run #3 and #1, I can see OK 1, 1, there is no blocking. I cannot find any explanation to address this issue, please help.

    Thanks again


    SAY NEVER

    Monday, July 2, 2012 9:49 AM
  • Hi XianZhong,

    Based on your code, there are two threads: one executes your while loop, and the other is your "new thread". How is run in OS, this is charged by OS. 

    Based on your description, it seems that the OS didn't call the "new thread", and hence, the first thread didn't finish the while loop. It happens sometimes, but not always. So how about restart a computer? Or try it another computer?

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, July 3, 2012 7:20 AM
    Moderator
  • Hi, Feng,

    Thanks again.

    I think i had gotten something to explain the different observations:

    In the case of  blocking (OK 1, 1 was not displayed ),  the value of very.a was read from the register, like EAX,  not the value already updated by the other thread , maybe compiler had optimized the code to just read the value qulickly from register,  to eliminate the blocking, we need to declare the a as volatile to prohibat the optimization.

    In other normal cases, the complier do the "right" thing: read the reference of very from register, add the offset to read the variable again, so the most recent value was caught

    Anyway, thanks again for the help.


    SAY NEVER

    Wednesday, July 4, 2012 5:22 AM