What is static variable
We know there is static variables in .Net which are bound to class not to objects. ie there will be only one memory location for a static variable in our AppDomain. If the same variable is accessed from different app domain it will get a different memory location. What is mean by one memory location per one static variable?Its simple. From where ever we change the value of the static variable, it will reflected throughout the .Net application / app domain.
static void Main() { Adder a1 = new Adder(); a1.Add(2, 3); Adder a2 = new Adder(); a2.Add(4, 5); Console.WriteLine(a1.Result); Console.WriteLine(a2.Result); } } //Demo purpose - Never use in your apps class Adder { static int _Result; internal int Result { get { return _Result; } } internal void Add(int n1, int n2) { _Result = n1 + n2; } }
You may easily understand that the result shown for a1 addition(2,3) is wrong. This is because the result of a2 addition (4,5) has overridden the previous static variable value. In other word the static variable have only one location to store its value.
Static variable v/s Instance variable
Its very simple. If the value of a static variable is changed from an instance method,that value will be available in all the other instance methods. Unlike the instance variable where there will be different memory location for storing values of the variable per instance.The beginners in programming sometime experienced but not worked in multi-threaded world, tend use static variables as it is the easiest medium to transport a value between disconnected classes.
internal static void TestStatic() { Adder a1 = new Adder(); a1.Add(2, 3);
Displayer.Display();
Adder a2 = new Adder();
a2.Add(4, 5);
Displayer.Display();
}
}
//Demo purpose - Never use in your apps
class Adder
{
internal static int _Result;
internal int Result { get { return _Result; } }
internal void Add(int n1, int n2)
{
_Result = n1 + n2;
}
}
class Displayer
{
internal static void Display()
{
Console.WriteLine(Adder._Result);
}
}
The Adder and Displayer class has no relation.In these disconnected scenarios people will prefer static variable to transport the value. It will display the values properly as long as there is single thread and the methods are invoked in order.
Static variable in threading scenario
The static variables will keep their values across threads as well. For example if one instance method of an object is executed inside the thread and it changes a static variable, the changed value will be available in another thread which is executing same instance method of another object. What is the problem if the value is reflected in other threads?
static void Main() { new Thread(() => { Adder a1 = new Adder(); a1.Add(2, 3); Thread.Sleep(100);//This is to simulate processing delay Displayer.Display(); }).Start(); new Thread(() => { Adder a2 = new Adder(); a2.Add(4, 5); Displayer.Display(); }).Start(); } } //Demo purpose - Never use in your apps class Adder { internal static int _Result; internal int Result { get { return _Result; } } internal void Add(int n1, int n2) { _Result = n1 + n2; } } class Displayer { internal static void Display() { Console.WriteLine(Adder._Result); } }
Here we can see the result of a1 addition (2,3) is overridden by the a2 addition. Also the behavior is not predictable. Sometimes the a2 addition may complete before a1 addition and a2 result might be 5 which is wrong.
lock to avoid unwanted manipulations
As everybody knows we can use the lock keyword to sequence the execution of code blocks so even if there are multiple threads running in parallel only one thread will get the lock and execute the code block at a time. In other words, we can sequence the execution of locked code block.
static object lockObj = new object(); internal static void TestStatic() { new Thread(() => { Adder a1 = new Adder(); lock (lockObj) { a1.Add(2, 3); Thread.Sleep(100);//This is to simulate processing delay Displayer.Display(); } }).Start(); new Thread(() => { lock (lockObj) { Adder a2 = new Adder(); a2.Add(4, 5); Displayer.Display(); } }).Start(); } } //Demo purpose - Never use in your apps class Adder { internal static int _Result; internal int Result { get { return _Result; } } internal void Add(int n1, int n2) { _Result = n1 + n2; } } class Displayer { internal static void Display() { Console.WriteLine(Adder._Result); } }
Here we can see things are working proper.But we lost the benefits of threading as its sequenced.
ThreadStatic
The simple static variable share common memory location inside the AppDomain. What if there is a way to have memory location per thread. So that the value of static variable will be available if the code is executed in same thread? Yes its an easy way to control problems of static variables which are accessed across the threads. But is it the silver bullet to solve the issue always? Lets see below scenario as well where the threads are coming from ThreadPool
internal static void TestStatic() { new Thread(() => { Adder a1 = new Adder(); a1.Add(2, 3); Thread.Sleep(100);//This is to simulate processing delay Displayer.Display(); }).Start(); new Thread(() => { Adder a2 = new Adder(); a2.Add(4, 5); Displayer.Display(); }).Start(); } } //Demo purpose - Never use in your apps class Adder { [ThreadStatic] internal static int _Result; internal int Result { get { return _Result; } } internal void Add(int n1, int n2) { _Result = n1 + n2; } } class Displayer { internal static void Display() { Console.WriteLine(Adder._Result); } }
This will keep keep separate memory location for static variables based on the thread. 2 Disconnected classes can access same value of static variable if their member function are executed in same thread. Else they will get different values. Here the application logic works fine.
ThreadPool
I don't think, I should explain what is thread pooling. In fact that is not the aim of this post. As mentioned in the previous section, the thread static values are stored based on the thread. So what if the same thread is coming back from the pool with a value which is set by us last time, when it was in use? Yes we are in trouble.
If we write code for taking thread from pool,we know this issue will happen.But what about ASP.Net where it internally uses the ThreadPool to take threads which are used to serve each request? We may not notice the fact and our code will fail during load testing / staging / production.
If we write code for taking thread from pool,we know this issue will happen.But what about ASP.Net where it internally uses the ThreadPool to take threads which are used to serve each request? We may not notice the fact and our code will fail during load testing / staging / production.
static void Main() { ThreadPool.SetMaxThreads(1,1); for( int i=0;i<10;i++) ThreadPool.QueueUserWorkItem((state) => { Adder a1 = new Adder(); a1.Increment(); Thread.Sleep(100);//This is to simulate processing delay Displayer.Display(); }); } } //Demo purpose - Never use in your apps class Adder { [ThreadStatic] internal static int _Result=0; internal int Result { get { return _Result; } } internal void Increment() { _Result += 1; } }
Here the class has altered to increment the value. We are always expecting the value 1 as in each thread the _Result is supposed to initialize to 0 due to its ThreadStatic behaviour. But we can see as the threads are reused, there will be values displayed which are higher than 1. So what is the solution?
ThreadStatic variables in ThreadPooling
Always make sure we are initializing the threadstatic variables where our thread handler is started. If possible use a using{} block to wrap our thread code so that in the constructor of using{} block object,we can initialize the thread static variables to their defaults.
No comments:
Post a Comment