#609 – Omit the Class Name for Static Members in the Same Class

Normally when you reference static members, you use the class name where they are defined to prefix the name of the member.  For example, if we have a static property in the Dog class called Motto and a static method called ListAllDogs, we’d use these static members from another class as follows:

    public class Program
    {
        static void Main()
        {
            // Reference static members in Dog from outside of Dog class
            Console.WriteLine("Dog motto: {0}", Dog.Motto);
            Dog.ListAllDogs();
        }
    }

However, if we access these static members from code within the Dog class itself, we can omit the class name when referencing the static members.

        // Dog.Bark
        public void Bark()
        {
            Console.WriteLine("{0} says Woof", Name);

            // Reference static members from within Dog class
            Console.WriteLine("Dog motto: {0}", Motto);
            ListAllDogs();
        }
Advertisements

#608 – Instance Methods Can Use Static Data

Instance methods in a class can make use of any of the public or private static data that belongs to that class.  (They can also make use of static data from other classes, provided that it is accessible).

    public class Dog
    {
        // Instance Properties
        public string Name { get; set; }
        public int Age { get; set; }

        // Static property
        public static Dog LastGuyThatBarked { get; protected set; }

        // Public static data
        public readonly static string TheDogMotto = "Man's Best Friend";

        // Private static data
        private static int TotalNumDogs = 0;

        public Dog(string name, int age)
        {
            Name = name;
            Age = age;
            TotalNumDogs++;
        }

        public void Bark()
        {
            Console.WriteLine("{0} says Woof", Name);

            // Access static property
            Dog.LastGuyThatBarked = this;

            // Access static data
            Console.WriteLine("There are {0} total dogs", Dog.TotalNumDogs);
            Console.WriteLine("Remember our motto: {0}", Dog.TheDogMotto);
        }
    }

#607 – When Do You Need the volatile Keyword?

The volatile keyword attached to a data field tells the compiler that this field may be read or written to by one or more threads at any time.  Values read from the field are therefore dependent on the timing of the different threads that might be writing to the field.  You can also think of it this way–the value of the field is “volatile”–it could change at any time, so the compiler should not make assumptions about the field’s value being static that would lead to incorrect optimizations.  I.e. Optimizations that lead to a thread reading a stale/incorrect value.

So you need to mark a field as volatile when

  • Different threads read and write the field’s value
  • You don’t protect access to the field using some synchronization technique (e.g. lock statement)

#606 – Use volatile Keyword to Fix Problems With Reading/Writing Shared Data

When you read data from one thread but write the data from a different thread, you can run into a problem where the thread reading the data will read stale/incorrect data.

You can prevent this behavior by marking the data field in question with the volatile keyword.  This indicates to the compiler that no optimizations should be done with respect to the storage location of this field and will prevent the problem of reading stale data.

Below is the earlier example, updated to include the volatile keyword.

        public static volatile bool runFlag = true;

        private static void RunUntilYouStopMe()
        {
            int i = 0;

            while (runFlag)
            {
                i++;
            }

            Console.WriteLine("I'm stopping");
        }

        static void Main()
        {
            Thread runThread = new Thread(new ThreadStart(RunUntilYouStopMe));
            runThread.Start();

            Thread.Sleep(1000);

            runFlag = false;
            Console.WriteLine("Main() has set runFlag to false");

            while (true)
            {
                Console.ReadLine();
                Console.WriteLine(".. runThread.IsAlive={0}", runThread.IsAlive);
            }
        }

Before the fix:

After the fix:

#605 – The Causes of Problems With Reading/Writing Shared Data from Multiple Threads

When you read data from one thread but write the data from a different thread, you can run into a problem where the thread reading the data will read stale/incorrect data.

The problem happens when the compiler, the runtime environment (e.g. JIT compiler) or the hardware optimizes the code in such a way that a thread ends up reading stale data and doesn’t have access to newer data written by a different thread.  As part of standard optimization techniques, a compiler may change the order of instructions being executed or it may choose to store a data value in a local register for efficiency.  When the latter occurs, one thread effectively ends up working with a different copy of the data.

To avoid these problems, you can do one of two things:

  • Protect access to the shared data using sychronization techniques
  • Use the volatile keyword for shared data fields

#604 – The Problem with Reading/Writing Shared Data from Different Threads

Reading shared data from a thread different to the one where you wrote the data, you may see unexpected results.  Consider the following:

    public class Program
    {
        public static bool runFlag = true;

        private static void RunUntilYouStopMe()
        {
            int i = 0;

            while (runFlag)
            {
                i++;
            }

            Console.WriteLine("I'm stopping");
        }

        static void Main()
        {
            Thread runThread = new Thread(new ThreadStart(RunUntilYouStopMe));
            runThread.Start();

            Thread.Sleep(1000);

            runFlag = false;
            Console.WriteLine("Main() has set runFlag to false");

            while (true)
            {
                Console.ReadLine();
                Console.WriteLine(".. runThread.IsAlive={0}", runThread.IsAlive);
            }
        }
    }

The background thread should run until the runFlag variable gets set to false.  We start the background thread and then set the flag to false on the main thread.  But running this code in Release|x86 mode, it turns out that the loop never exits, even though we set runFlag to false.

This is caused by a compiler optimization related to our runFlag variable.

#603 – Using Constants Can Force Recompilation

Here’s an additional difference between a static readonly field and a constant.  Let’s say that you have a class that includes both a public static readonly field and a public constant.

public static readonly string ReadonlyMotto = "Man's Best Friend";
public const string ConstantMotto = "Man's Best Friend";

Now assume that you have two assemblies, as follows.

At this point, let’s say that you want to change the two elements that contain the dog mottos, i.e. the readonly field and the constant.  So you change the values and re-compile Dog.dll but do not re-compile DogViewer.exe.

At this point, something interesting happens at runtime if you run DogViewer.exe.

  • DogViewer sees the new value of the readonly field
  • DogViewer does not see the new value of the constant

This happens because when you compile code that uses a constant, the value of the constant is included in the generated code.