The ThreadStatic attribute


With applications moving to a multi-threaded model the dynamic of instance management is also changing. One such instance was the need for a background thread creating an instance and accessing its static field. Here’s something weird I needed. I needed type to be have its own instance and to not share its values across different threads. I started off with making it a static and  thinking more on a class level instance management. Something like singleton instance  for a particular instance and stuff. It was turning into one complicated code work. But it turns out Microsoft had already predicted this.

There is an attribute in .NET called ThreadStatic. This is what MSDN has to say about it

“A static field marked with ThreadStaticAttribute is not shared between threads. Each executing thread has a separate instance of the field, and independently sets and gets values for that field. If the field is accessed on a different thread, it will contain a different value.”

This was convenient. But there it came with certain caveats.

  1. It works only with fields
  2. Do not specify initial value for fields as initialization occurs only once, when the class constructor executes and therefor affects only one thread.
  3. You can rely on the field being initialized to its default values type or to Nothing if it’s a reference type

Also another precautionary note here is Dont inherit from it. Turns out you cant because its been sealed of via  an attribute  Attribute ( Inheritance = false)

Before we proceed one prerequisite is to have a  basic understanding of the Task Paralel library.  Lets see this in action. I’ve posted below is a code snippet.

1.  internal  class StaticThreasdAttributesDemo
2.    {
3.        internal void ThreadStaticDemo()
4.        {
5.            Console.ForegroundColor = ConsoleColor.Yellow;
6.            Console.WriteLine("** Showing an example of Static value with the attribute ThreadStatic example ");
7.            Console.ForegroundColor = ConsoleColor.White;
8.            ThreadStaticAttributedFieldClass.Number = 201;
9.            ThreadStaticAttributedFieldClass mc = new ThreadStaticAttributedFieldClass("Method");
10.            Console.WriteLine("On start Number value is " + ThreadStaticAttributedFieldClass.Number);

11.           Task tsk = new Task(() =>
12.           {
13.                Console.WriteLine(" ** In Thread ONE Start point Static Number value is " + ThreadStaticAttributedFieldClass.Number + " **");//6
14.                Console.WriteLine(" ** In Thread ONE Method instance Number value is " + mc.NumberValue + " **");//5

15.                ThreadStaticAttributedFieldClass.Number = 101;
16.                ThreadStaticAttributedFieldClass mc1 = new ThreadStaticAttributedFieldClass("ONE");
17.                Console.WriteLine(" ** In Thread ONE Number value is " + mc1.NumberValue + " **");//6

18.                Console.WriteLine(" ** In Thread ONE Endpoint Static Number value is " + ThreadStaticAttributedFieldClass.Number + " **");//6
19.            });

20.            Task tsk2 = new Task(() =>
21.            {
22.                Console.WriteLine(" ** In Thread TWO start point Static  Number value is " + ThreadStaticAttributedFieldClass.Number + " **");//7
23.                Console.WriteLine(" ** In Thread TWO Method instance Number value is " + mc.NumberValue + " **");//6
24.                ThreadStaticAttributedFieldClass.Number = 11;
25.                ThreadStaticAttributedFieldClass mc2 = new ThreadStaticAttributedFieldClass("TWO");
26.                Console.WriteLine(" ** In Thread TWO Number value is " + mc2.NumberValue + " **");//7

27.                Console.WriteLine(" ** In Thread TWO in Endpoint Static  Number value is " + ThreadStaticAttributedFieldClass.Number + " **");//7
28.            });

29.            tsk.Start();

30.            tsk2.Start();

31.            Console.WriteLine("On ending Number value is " + ThreadStaticAttributedFieldClass.Number);

32.            while (!tsk.IsCompleted || !tsk2.IsCompleted)
33.            {
34.                //Console.WriteLine("Waiting for thread operation to complete...");
35.            }

36.           Console.ForegroundColor = ConsoleColor.Yellow;
37.            Console.WriteLine("** On end ThreadStatic attribute labeled Static value example \n\n ");
38.            Console.ForegroundColor = ConsoleColor.White;

39.            Console.ReadKey();
40.        }

41.       class ThreadStaticAttributedFieldClass 
42.        {
43.            [ThreadStatic] 44.            public static int Number = 4;

45.            static ThreadStaticAttributedFieldClass()
46.            {
47.                Number = 24;
48.                Console.WriteLine(" <-------- In side Static for ThreadStaticAttributedFieldClass : Number values is " + Number + "  ------->");
49.            }

50.            public int NumberValue
51.            {
52.                get { return Number; }
53.            }

54.            public ThreadStaticAttributedFieldClass(string st = "")
55.            {
56.                Number++;
57.                string mesage = string.IsNullOrEmpty(st)
58.                                    ? " ----- ThreadStatic constructor called " + Number + " -----"
59.                                    : " ----- ThreadStatic constructor called by " + st + " " + Number + " -----";
60.                Console.WriteLine(mesage);
61.            }
62.        }
63.    }

Now heres the main program

  private static void Main()
        {
            Console.WriteLine("*******************************\n\n");
            var demo3 = new StaticThreasdAttributesDemo();
            demo3.ThreadStaticDemo();
            Console.WriteLine("*******************************\n\n");
            Console.ReadKey();
        }

Let me walk thorugh some crucial points

  1. The Field called Number  ( Line no 43 and  44) in ThreadStaticAttributedFieldClass is static . Number will be 4 when initialized but 24 when static constructor is initialzed. That’s it never will the field be reinitialized to 4 nor will the constructor ever be called.
  2. I’ve made an instance for  ThreadStaticAttributedFieldClass  called mc in the method ThreadStaticDemo ( Line 3)
  3. The method changes values to 201 and creates a new instance of the class where the constructor increments it. Number is now 202
  4. I’ve created two task to run in the background tsk and tsk1 (Line 11, 20)
  5. Then we wait for the task to complete.(Line 32)
  6. The first thread to print values is thread TWO ( Line no 22) where the value in Number is 0.  Now this is important Number is not 202 or 24. The ThreadStatic attribute resets the field to default value ( incase of int its 0) for the given field Number every time a new thread tries accesing it. In this case tsk and tsk1 both end up printinng 0 for the method level instance mc and local instance mc1 and the static access ThreadStaticAttributedFieldClass.Number
  7. tsk and tsk1 both update the ThreadStaticAttributedFieldClass.Number to 101 and 21 respectively and create a local instance for it. The printed value from the constructor is different even though the field is static.
  8. On printing values again we find each thread working on its own set of different set  of values for Number.

To summarize what ThreadStatic does it will give a thread its own initialized instance of a static field with thread safety. This is harder to manage in a singleton pattern

Advertisements

2 thoughts on “The ThreadStatic attribute

  1. Its really a nice article on ThreadStatic attribute. We can have a thread safe static field now which is difficult to have it in singleton patterns. This also fulfills the need for a background thread creating an instance and accessing its static field seperately in individual thread.
    Nice One…!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s