Working With Thread Local Storage (TLS) in C#


Thread-local storage (TLS) is a computer programming method that uses static or global memory local to a thread.  All threads of a process share the virtual address space of the process. The local variables of a function are unique to each thread that runs the function. However, the static and global variables are shared by all threads in the process. With thread local storage (TLS), you can provide unique data for each thread that the process can access using a global index. One thread allocates the index, which can be used by the other threads to retrieve the unique data associated with the index.

In the .NET Framework version 4, you can use the System.Threading.ThreadLocal<T> class to create thread-local objects.

System.Threading.ThreadLocal<T>

where T Specifies the type of data stored per-thread. The ThreadLocal(Of T) type exposes the following members.

Constructors

  • ThreadLocal(T)- The constructer used to initialize the ThreadLocal(T) instance.
  • ThreadLocal(T)(Tfunc(T))- This constructer is used to initialize the ThreadLocal(Of T) instance with the specified valueFactory function.

Properties

  • Value- This property is used to get or set the value of this instance for the current thread.
  • IsValueCreated- This property is used to get whether a value is initialized on the current thread.

Methods

  • Dispose()- This method is used to release all resources used by the current instance of the ThreadLocal(Of T) class.
  • Equals(Object)- This method determines whether the specified Object is equal to the current Object. (Inherited from Object.)
  • Finalize()- This method is used to release the resources used by this ThreadLocal(Of T) instance. (Overrides Object.Finalize.)
  • GetHashCode()- This method serves as a hash function for a particular type. (Inherited from Object.)
  • GetType()- This method gets the Type of the current instance. (Inherited from Object.)
  • MemberwiseClone()- This method is uesd to create a shallow copy of the current Object. (Inherited from Object.)
  • ToString()- This method is uesd to create and return a string representation of this instance for the current thread. (Overrides Object.ToString.)
     

The .NET Framework provides dynamic data slots that are unique to a combination of thread and application-domain. There are two types of data slots: named slots and unnamed slots. Both are implemented by using the LocalDataStoreSlot structure.

  • To create a named data slot, use the Thread.AllocateDataSlot or Thread.GetNamedDataSlot method. To get a reference to an existing named slot, its name to the GetNamedDataSlot method.
  • To create an unnamed data slot, use the Thread.AllocateDataSlot method.

For both named and unnamed slots, use the Thread.SetData andThread.GetData methods to set and retrieve the information in the slot. These are static methods that always act on the data for the thread that is currently executing them.

Named slots can be convenient, because you can retrieve the slot when you need it by ing its name to the GetNamedDataSlot method, instead of maintaining a reference to an unnamed slot. However, if another component uses the same name for its thread-relative storage and a thread executes code from both your component and the other component, the two components might corrupt each other's data. (This scenario assumes that both components are running in the same application domain, and that they are not designed to share the same data.)

The following example shows how to use ThreadLocal(T):

using System;
using System.Threading;
namespace ThreadLocalStorage
{
    class akshay
    {
             public static void WriteError()
        {
            Console.WriteLine("Error number = " + Thread.GetData(Thread.GetNamedDataSlot("ErrNo")));
            Console.WriteLine("Error source = " + Thread.GetData(Thread.GetNamedDataSlot("ErrSource"))
        } 
        public static void SetError()
        {
            Random r = new Random();
            Thread.SetData(Thread.GetNamedDataSlot("ErrNo"), r.Next(100));
            Thread.SetData(Thread.GetNamedDataSlot("ErrSource"), Thread.CurrentThread.Name);
            WriteError();
        }
        public static void Main()
        {
            Thread.AllocateNamedDataSlot("ErrNo");
            Thread.AllocateNamedDataSlot("ErrSource");
            Thread th2 = new Thread(new ThreadStart(SetError));
            th2.Name = "t2";
            th2.Start();
            Thread th3 = new Thread(new ThreadStart(SetError));
            th3.Name = "t3";
            th3.Start();
            Thread.FreeNamedDataSlot("ErrNo");
            Thread.FreeNamedDataSlot("ErrSource");
            Console.Read();
        }
    }
}

Output

img1.jpg

We can create thread local storage in the managed environment. Depending on your application, it may be necessary for you to have a static field of a class that is unique for each thread that the class is used in. Doing so is trivially easy in the majority of the cases in C#. If you have a static field that must be thread relative, simply adorn it with the ThreadStaticAttribute attribute. Once you do that, the field will be initialized for each thread that accesses it. Under the covers, each thread is given its own thread relative location to save the value or reference. However, when using references to objects, be careful with your assumptions about the object's creation. The following code shows a pitfall to avoid.

using System;
using
System.Threading;
namespace ThreadLocalStorage
{
public class TLS
    {
        public TLS()
        {
            Console.WriteLine("Creating TLS Class");
        }
     }
 public class TLSFlied
        {
            [ThreadStatic]
            public static TLS Tdata = new TLS();       
        }
  public class EntryPoint
        {
            private static void ThreadFun()
            {
                Console.WriteLine("Thread {0} starting.....",Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("TData for this thread is \"{0}\"",TLSFlied.Tdata);
                Console.WriteLine("thread {0} exiting",Thread.CurrentThread.ManagedThreadId);
            }
            static void Main()
            {
                Thread t1 = new Thread(new ThreadStart(EntryPoint.ThreadFun));
                Thread t2 = new Thread(new ThreadStart(EntryPoint.ThreadFun));
                t1.Start();
                t2.Start();
                Console.Read();
            }
        }
}

Output

img2.jpg

Resources

Thread- local storage of data in .NET
Use Thread Local Storage to Thread Specific Data
Storing Data in C#
Windows Azure - Local Storage Feature


Similar Articles