#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.

#602 – Initializing Fields in a Class

You can initialize instance-level fields in a class when you declare them.  If you do not initialize them, all fields are initialized to default values (0 for numeric types, null for reference types).

In the fragment of the Dog class below, we initialize two instance-level fields and one static field.

    public class Dog
    {
        // Instance fields
        public string Name = "Bowser";
        public int Age = 1;

        // Static fields (one for entire type, rather than 1/instance)
        public static string CanineMotto = "We're here to serve you";

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

        public Dog() { }
    }
            Dog myDog = new Dog();
            Console.WriteLine("My dog {0} is aged {1}", myDog.Name, myDog.Age);

            Dog yourDog = new Dog("Kirby", 15);
            Console.WriteLine("Your dog {0} is aged {1}", yourDog.Name, yourDog.Age);

            Console.WriteLine("Dog motto: {0}", Dog.CanineMotto);

#601 – A Class Can Both Inherit from A Parent Class and Implement an Interface

Every user-defined class inherits from exactly one other class.  You can either explicitly specify the class to inherit from, or the class can implicitly inherit from System.Object.

A user-defined class may optionally implement one or more interfaces.

A class may therefore both inherit from a parent class and also implement one or more interfaces.  All of the declarations listed below are valid class declarations.  (Class members are not shown).

// Implicitly inherits from System.Object
public class Movie
{
}

// Explicitly inherit from a class
public class Terrier : Dog
{
}

// Implement one or more interfaces
public class Dog : IBark, IFetch
{
}

// Inherit and implement an interface
public class BorderCollie : Dog, IHerd, IObsess
{
}

#600 – Reversing the Elements in an Array

You can use the static Array.Reverse method to reverse the order of elements in an array.  This modifies the contents of the array that you pass to Array.Reverse.

            int[] someNumbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            DumpArrayContents(someNumbers);

            // Reverse the elements using Array.Reverse
            Array.Reverse(someNumbers);
            DumpArrayContents(someNumbers);

Note that this Reverse method is different from the IEnumerable<int>.Reverse method, which does not modify the contents of the array, but just returns a reversed sequence.

// IEnumerable<int>.Reverse
int[] moreNumbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
IEnumerable<int> reversedNums = moreNumbers.Reverse();
DumpArrayContents(moreNumbers);
DumpArrayContents(reversedNums);

#599 – Copying an Array Onto Another Array

You can use the Array.CopyTo method to copy one entire array into another array.  The first array must be the same size or smaller than the second array.

You specify the index into the second array where you want to start copying the first array.  (0 indicates the first element of the second array).  The portion of the second array starting at this index must be large enough to contain the entire first array.

        static void Main()
        {
            int[] bigNumbers = {400, 500, 600};
            int[] smallerNumbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

            // Copy big number array into middle of small number array
            // Start at 4th element (index = 3)
            bigNumbers.CopyTo(smallerNumbers, 3);

            // Dump them both out
            DumpArrayContents(bigNumbers);
            DumpArrayContents(smallerNumbers);
        }



Note that if the portion of the destination array that starts at the specified index is not large enough to contain the source array, you will get an ArgumentException.

You can only use CopyTo with one-dimensional arrays.

#598 – Clearing an Array or a Subset of an Array

You can clear (zero out) an array or a subset of an array with a call to the static Array.Clear method.  You pass the array into the method, as well as an indication of what portion of the array you want to clear.

Dog kirby = new Dog("Kirby", 15);
string[] someToys = kirby.FavoriteToys();
int[] someNumbers = kirby.FavoriteNumbers();

DumpArrayContents(someToys, someNumbers);

// Now clear each array
Array.Clear(someToys, 0, someToys.Length);  // Clear entire array
Array.Clear(someNumbers, 1, 2);   // Clear 2nd/3rd elements
DumpArrayContents(someToys, someNumbers);

Notice that after we call Clear on the array of string elements, each element becomes an empty string.  For the array of int values, the two elements that we cleared become zero.

If you call Array.Clear on an array contained reference-typed objects, the values that are cleared become null.

Dog[] pack = { new Dog("Kirby", 15), new Dog("Jack", 17), new Dog("Ruby", 1) };

DumpArrayContents(pack);

Array.Clear(pack, 0, pack.Length);
DumpArrayContents(pack);

#597 – Returning an Array from a Method

You can return an array from a method just like you can return any other reference-typed object from a method.  The array will be instantiated within the method and a reference to the new object is what is returned to the calling code.

Assume that we have a method declared like this in a Dog class:

public string[] FavoriteToys()

We can then call this method as follows:

            Dog kirby = new Dog("Kirby", 15);

            string[] favToys = kirby.FavoriteToys();

            foreach (string toy in favToys)
                Console.WriteLine(toy);


We could also just use the method call in the body of the foreach loop:

            foreach (string toy in kirby.FavoriteToys())
                Console.WriteLine(toy);