Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

shared variable between two threads behaves differently from shared property

In his excellent treatise on threading in C#, Joseph Albahari proposed the following simple program to demonstrate why we need to use some form of memory fencing around data that is read and written by multiple threads. The program never ends if you compile it in Release mode and free-run it without debugger:

  static void Main()
  {
     bool complete = false;
     var t = new Thread(() =>
     {
        bool toggle = false;
        while (!complete) toggle = !toggle;
     });
     t.Start();
     Thread.Sleep(1000);
     complete = true;                  
     t.Join(); // Blocks indefinitely
  }

My question is, why does the following slightly modified version of the above program no longer block indefinitely??

class Foo
{
  public bool Complete { get; set; }
}

class Program
{
  static void Main()
  {
     var foo = new Foo();
     var t = new Thread(() =>
     {
        bool toggle = false;
        while (!foo.Complete) toggle = !toggle;
     });
     t.Start();
     Thread.Sleep(1000);
     foo.Complete = true;                  
     t.Join(); // No longer blocks indefinitely!!!
  }
}

Whereas the following still blocks indefinitely:

class Foo
{
  public bool Complete;// { get; set; }
}

class Program
{
  static void Main()
  {
     var foo = new Foo();
     var t = new Thread(() =>
     {
        bool toggle = false;
        while (!foo.Complete) toggle = !toggle;
     });
     t.Start();
     Thread.Sleep(1000);
     foo.Complete = true;                  
     t.Join(); // Still blocks indefinitely!!!
  }
}

As does the following:

class Program
{
  static bool Complete { get; set; }

  static void Main()
  {
     var t = new Thread(() =>
     {
        bool toggle = false;
        while (!Complete) toggle = !toggle;
     });
     t.Start();
     Thread.Sleep(1000);
     Complete = true;                  
     t.Join(); // Still blocks indefinitely!!!
  }
}
like image 848
dmg Avatar asked May 01 '12 15:05

dmg


People also ask

Are variables shared between threads?

Threads share all global variables; the memory space where global variables are stored is shared by all threads (though, as we will see, you have to be very careful about accessing a global variable from multiple threads).

When two threads access a shared variable at the same time it is called?

A race condition occurs when two threads access a shared variable at the same time. The first thread reads the variable, and the second thread reads the same value from the variable.

How do you pass variables between threads in python?

We can share a local variable between threads using a queue. The queue must be shared and accessible to each thread and within the function where the local variable is defined and used. For example, we can first create a queue. Queue instance.

Can static variables be used for inter thread communication?

Static variables are indeed shared between threads, but the changes made in one thread may not be visible to another thread immediately, making it seem like there are two copies of the variable.


1 Answers

In the first example Complete is a member variable and could be cached in register for each thread. Since you aren't using locking, updates to that variable may not be flushed to main memory and the other thread will see a stale value for that variable.

In the second example, where Complete is a property, you are actually calling a function on the Foo object to return a value. My guess would be that while simple variables may be cached in registers, the compiler may not always optimize actual properties that way.

EDIT:

Regarding the optimization of automatic properties - I don't think there is anything guaranteed by the specification in that regard. You are essentially banking on whether or not the compiler/runtime will be able to optimize out the getter/setter or not.

In the case where it is on the same object, it seems like it does. In the other case, it seems like it does not. Either way, I wouldn't bet on it. The easiest way to solve this would be to use a simple member variable and mark is as volotile to ensure that it is always synced with main memory.

like image 59
Eric Petroelje Avatar answered Oct 05 '22 22:10

Eric Petroelje