Thread storage

Thread-relative static fields and data slots are the two ways in which we can store data that is unique to the thread and application domain. Thread-relative static fields are defined at compile time and provide the best performance. Another benefit is that they do compile-time type checking. These fields are used when the requirement about what kind of data to be stored is clear beforehand. 

Thread-relative static fields can be created using ThreadStaticAttribute.

There are scenarios where these storage requirements may arise at runtime. In such scenarios, we can opt for data slots. These are a bit slower than static fields. Since these are created at runtime, they store information as an object type. It is important for us to convert these objects into their respective types before using them.

.NET Framework allows us to create two types of data slots: named data slots and unnamed data slots. Named data slots use the GetNamedDataSlot method so that we can retrieve it as and when required. However, one disadvantage of NamedDataslot is when two threads from the same application domain use the same data slot in two different components of code and execute them at the same time. When this happens, they can corrupt each other's data.

ThreadLocal<T> can be used to create local data storage.

These two ways of storing data can be referred to as thread-local storage (TLS). A couple of the benefits of managed TLS are as follows:

  • Within an application domain, one thread cannot modify data from another thread, even when both threads use the same field or slot
  • When a thread accesses the same field or slot from multiple application domains, a separate value is maintained in each application domain

Now, we will jump into an example and look at how the ThreadStatic attribute can be used. In the following example, a static variable is being defined and decorated with the ThreadStatic attribute. This ensures that each thread has its own copy of the variable. When you execute the following program, you will observe that _intvariable goes up to 6 for each thread:

[ThreadStatic]
public static int _intvariable;
public static void ThreadStaticSample()
{
//Start three threads
new Thread(() =>
{
for (int i = 0; i <= 5; i++)
{
_intvariable++;
Console.WriteLine($"Thread Id:{Thread.CurrentThread.ManagedThreadId}, Int field Value:{_intvariable}");
}
}).Start();

new Thread(() =>
{
for (int i = 0; i <= 5; i++)
{
_intvariable++;
Console.WriteLine($"Thread Id:{Thread.CurrentThread.ManagedThreadId}, Int field Value:{_intvariable}");
}
}).Start();

new Thread(() =>
{
for (int i = 0; i <= 5; i++)
{
_intvariable++;
Console.WriteLine($"Thread Id:{Thread.CurrentThread.ManagedThreadId}, Int field Value:{_intvariable}");
}
}).Start();

}

The following screenshot shows the output of running the preceding program. Comment the ThreadStatic attribute and run the program again—you will find that the _intvariable value goes up to 18 as each thread updates its value:

Let's see how we can use ThreadLocal<T> to create local storage:

 public static ThreadLocal<string> _threadstring = new ThreadLocal<string>(() => {
return "Thread " + Thread.CurrentThread.ManagedThreadId; });
public static void ThreadLocalSample()
{

//Start three threads
new Thread(() =>
{
for (int i = 0; i <= 5; i++)
{
Console.WriteLine($"First Thread string :{_threadstring}");
}
}).Start();

new Thread(() =>
{
for (int i = 0; i <= 5; i++)
{
Console.WriteLine($"Second Thread string :{_threadstring}");
}
}).Start();

new Thread(() =>
{
for (int i = 0; i <= 5; i++)
{
Console.WriteLine($"Third Thread string :{_threadstring}");
}
}).Start();

}

The output of the preceding code is as follows:

Now that we've understood how to manage threads, let's look at how to synchronize data in multithreading.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.144.59