Recipe18.9.Storing Thread-Specific Data Privately


Recipe 18.9. Storing Thread-Specific Data Privately

Problem

You want to store thread-specific data discovered at runtime. This data should be accessible only to code running within that thread.

Solution

Use the AllocateDataSlot, AllocateNamedDataSlot, or GetNamedDataSlot method on the Thread class to reserve a thread local storage (TLS) slot. Using TLS, a large object can be stored in a data slot on a thread and used in many different methods. This can be done without having to pass the structure as a parameter.

For this example, a structure called Data here represents a structure that can grow to be very large in size:

 public class Data {     // Application data is stored here. } 

Before using this structure, a data slot has to be created in TLS to store the structure. GetNamedDataSlot is called to get the appDataSlot. Since that doesn't exist, the default behavior for GetNamedDataSlot is to just create it. The following code creates an instance of the Data structure and stores it in the data slot named appDataSlot:

 Data appData = new Data( ); Thread.SetData(Thread.GetNamedDataSlot("appDataSlot"), appData); 

Whenever this structure is needed, it can be retrieved with a call to THRead.GetData. The following line of code gets the appData structure from the data slot named appDataSlot:

 Data storedappdata = (Data)Thread.GetData(Thread.GetNamedDataSlot("appDataSlot")); 

At this point, the storedappdata structure can be read or modified. After the action has been performed on the storedappdata structure, storedappdata must be placed back into the data slot named appDataSlot:

 Thread.SetData(Thread.GetNamedDataSlot("appDataSlot"), appData); 

Once the application is finished using this structure, the data slot can be released from memory using the following method call:

 Thread.FreeNamedDataSlot("appDataSlot"); 

The HandleClass class in Example 18-6 shows how TLS can be used to store a structure.

Example 18-6. Using TLS to store a structure

 using System; using System.Threading; public class HandleClass {     public static void Main( )     {         // Create structure instance and store it in the named data slot.         Data appData = new Data( );         Thread.SetData(Thread.GetNamedDataSlot("appDataSlot"), appData);         // Call another method that will use this structure.         HandleClass.MethodB( );         // When done, free this data slot.         Thread.FreeNamedDataSlot("appDataSlot");     }     public static void MethodB( )     {         // Get the structure instance from the named data slot.         Data storedappdata = (Data)Thread.GetData(           Thread.GetNamedDataSlot("appDataSlot"));         // Modify the Storedappdata structure.         // When finished modifying this structure, store the changes back         // into the named data slot.         Thread.SetData(Thread.GetNamedDataSlot("appDataSlot"),                         storedappdata);         // Call another method that will use this structure.         HandleClass.MethodC( );     }     public static void MethodC( )     {         // Get the structure instance from the named data slot.         Data storedappdata =             (Data)Thread.GetData(Thread.GetNamedDataSlot("appDataSlot"));         // Modify the storedappdata structure.         // When finished modifying this structure, store the changes back into         // the named data slot.         Thread.SetData(Thread.GetNamedDataSlot("appDataSlot"), storedappdata);     } } 

Discussion

Thread local storage is a convenient way to store data that is usable across method calls without having to pass the structure to the method or even without knowledge about where the structure was actually created.

Data stored in a named TLS data slot is available only to that thread; no other thread can access a named data slot of another thread. The data stored in this data slot is accessible from anywhere within the thread. This setup essentially makes this data global to the thread.

To create a named data slot, use the static Thread.GetNamedDataSlot method. This method accepts a single parameter, name, that defines the name of the data slot. This name should be unique; if a data slot with the same name exists, then the contents of that data slot will be returned and a new data slot will not be created. This action occurs silently; there is no exception thrown or error code available to inform you that you are using a data slot someone else created. To be sure that you are using a unique data slot, use the Thread.AllocateNamedDataSlot method. This method throws a System.ArgumentException if a data slot already exists with the same name. Otherwise, it operates similarly to the GetNamedDataSlot method.

It is interesting to note that this named data slot is created on every thread in the process, not just the thread that called this method. This fact should not be much more than an inconvenience to you, though, since the data in each data slot can be accessed only by the thread that contains it. In addition, if a data slot with the same name was created on a separate thread and you call GetNamedDataSlot on the current thread with this name, none of the data in any data slot on any thread will be destroyed.

GetNamedDataSlot returns a LocalDataStoreSlot object that is used to access the data slot. Note that this class is not creatable through the use of the new keyword. It must be created through one of the AllocateDataSlot or AllocateNamedDataSlot methods on the Thread class.

To store data in this data slot, use the static Thread.SetData method. This method takes the object passed in to the data parameter and stores it in the data slot defined by the dataSlot parameter.

The static THRead.GetData method retrieves the object stored in a data slot. This method retrieves a LocalDataStoreSlot object that is created through the Thread.GetNamedDataSlot method. The Getdata method then returns the object that was stored in that particular data slot. Note that the object returned might have to be cast to its original type before it can be used.

The static method Thread.FreeNamedDataSlot will free the memory associated with a named data slot. This method accepts the name of the data slot as a string and, in turn, frees the memory associated with that data slot. Remember that when a data slot is created with GetNamedDataSlot, a named data slot is also created on all of the other threads running in that process. This is not really a problem when creating data slots with the GetNamedDataSlot method because, if a data slot exists with this name, a LocalDataStoreSlot object that refers to that data slot is returned, a new data slot is not created, and the original data in that data slot is not destroyed.

This situation becomes more of a problem when using the FreeNamedDataSlot method. This method will free the memory associated with the data slot name passed in to it for all threads, not just the thread that it was called on. Freeing a data slot before all threads have finished using the data within that data slot can be disastrous to your application.

A way to work around this problem is to not call the FreeNamedDataSlot method at all. When a thread terminates, all of its data slots in TLS are freed automatically. The side effect of not calling FreeNamedDataSlot is that the slot is taken up until the garbage collector determines that the thread the slot was created on has finished and the slot can be freed.

If you know the number of TLS slots you need for your code at compile time, consider using the ThreadStaticAttribute on a static field of your class to set up TLS-like storage.

See Also

See the "Thread Local Storage and Thread Relative Static Fields," "ThreadStaticAttribute Attribute," and "Thread Class" topics in the MSDN documentation.



C# Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2004
Pages: 424

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net