Multithreading: using the stack as storage

In the last post of the series we’ve seen that all threads have a “private” stack (which you can easily configure when you create a new thread or by using the editbin.exe utility, when you need to change the stack size of the main thread).

As I said, most (if not all) interactions we have with the stack will be “defined” by the compiler (I’m thinking about the general managed apps we write daily). However, we can also use the thread’s stack explicitly from our code. This might help you when you don’t need to share information between threads (when having multiple copies of data is possible and not too penalizing from a performance point of view). Notice that isolating data is a good approach for allowing scalability since we don’t need any data synchronization overhead in these scenarios.

In a managed program, there are two ways to access the thread local storage:

  1. we can annotate a static field with the ThreadStaticAttribute (notice that this will only work for static fields!). Fields annotated with this attribute are allocated on the TLS and each thread has its own copy of of each of them;
  2. when we don’t know which fields are needed, we can always use the TLS API for allocating a (named) data slot and for adding and removing data from those slots.

The attribute option is recommended and we should use it whenever possible. However, option 2 is the way to go when we don’t know which fields should be allocated on the TLS at compile time. We’ll take a look at both approaches, starting with the attribute usage… Take a look at the following code:

class Program { 
   class TestContainer        {
      [ThreadStatic]
      private static IDictionary<Int32, String> _items =
                                               new Dictionary<Int32, String>(); 
      //wrap the field with a property
       public static IDictionary<Int32, String> Items {
                get {
                    if(_items == null )
                    {
                        _items = new Dictionary<Int32, String>();
                    }
                    return _items;
                }
       } 
       public void AddItem(Int32 key,String description) {
                //always use the Items property
                Items.Add(key,description);
       }

public static void AddAndPrint(Int32 top) {
     var testContainer = new TestContainer();
     for (var i = 0; i < top; i++) {
        testContainer.AddItem(i, String.Concat("item ", i));
     }
     foreach (var item in TestContainer.Items) {
         Console.WriteLine("Thread: {0} — Key:{1} — Value: {2}",
                                  Thread.CurrentThread.ManagedThreadId,
                                  item.Key,
                                  item.Value);
      }
}

static void Main(string[] args)  {
     var thread1 = new Thread(obj => {
                                                var top = Convert.ToInt32(obj);
                                                AddAndPrint(top);
     });

     thread1.Start(100);
     AddAndPrint(200);
     thread1.Join();

}
}

The first important thing you need to keep in mind is that you should always check for lazy initialization. Don’t forget that even if you initialize the static field from the static constructor (the previous code does that because it initialized the field on the spot of declaration), that initialization code will only run once. That’s why we’ve wrapped the field with a static property which checks for null before returning a reference to that field. If we hadn’t done that, then the second thread would end up throwing a null reference exception!

The rest of the code is really simple. We’ve added a method (AddAndPrint) to put all the code we wanted to execute in both threads. Notice that we’re using the AddItem method for adding an item to a dictionary. If each thread didn’t have it’s own copy of the dictionary, we’d be getting exceptions for adding items with duplicate keys.

Now, let’s see how we can use the dynamic TLS approach…Take a look at the next snippet (I’m only showing the code for the class):

class TestContainer: IDisposable {
   private static readonly String _slotName = Guid.NewGuid().ToString();
   public static IDictionary<Int32, String> Items {
         get {
            var slot = GetNamedSlot();
            return (IDictionary<Int32, String>) Thread.GetData(slot);
         }
   }
   private static LocalDataStoreSlot GetNamedSlot() {
    &a
mp;#
160;  var slot = Thread.GetNamedDataSlot(_slotName);
       //check for dictionary
       if( Thread.GetData(slot ) == null ) {
           //add new empty dictionary to slot
           Thread.SetData(slot, new Dictionary<Int32, String>() );
       }
       return slot;
   }
   public void AddItem(Int32 key, String description) {
       Items.Add(key, description);
   }
   public void Dispose() {
                Thread.FreeNamedDataSlot(_slotName);
    }
}

As you can see, the only thing that changes is the way we get the storage for the dictionary. Creation of new slots can also be achieved by calling the AllocateNamedDataSlot method (not used in the previous example because the GetNamedDataSlot initializes a new slot when one doesn’t exist):

public static LocalDataStoreSlot AllocateDataSlot();
public static LocalDataStoreSlot AllocateNamedDataSlot(string name);

Both methods return an instance of type LocalDataStoreSlot, which is used for encapsulating an entry on the local thread storage. Notice that if you use the overload which doesn’t receive a name, then you must hold on to the returned LocalDataStoreSlot or you’ll never be able to get a reference to it in the future.

Typically, you’ll only use one of these methods if you want to allocate several slots at startup. Most of the time, calling the GetNamedDataSlot is all you need because it will lazy allocate a slot if none exists with that name. Notice that we also check for the existence of a valid dictionary on the named slot we retrieve from that method call (in order to ensure proper initialization of the dictionary in all threads).

Finally, notice that we’re feeing the data slot by calling the FreeNamedDataSlot method (though this might not free memory as soon as you might expect because the thread holds a reference to each slot that gets created). I’ve opted for putting that code inside the Dispose method, letting clients call wrap class usage in a using block.

Before ending, it’s important to understand that this last option (directly using slots for storing data) is more flexible, but much worst (from a performance point of view). You should only use it when you can’t use the thread static attribute at compile time!

And that’s it for today…keep tuned for more on multithreading…

Advertisements

~ by Luis Abreu on May 6, 2009.

5 Responses to “Multithreading: using the stack as storage”

  1. Hello!!! Keeping up with the latest features and fashions of strollers these days is a must! http://forums.slimdevices.com/member.php?u=27226 ; – >>> 😉 %%%

  2. Hi
    Very nice forum
    Best regards

  3. Hi There!

    I just wanted to drop by and say hello. I was trolling this community for a long time now, but haven”t made a post.

    I am from Algiers and enjoy video games like half life and xbox. I hope to get a lot out of this forum .

    Thank you for having me 🙂

    Marc

  4. Great site. Keep doing.

  5. We repair houses In Maryland,US.
    Personal / Surface remodelings,
    suitable prices,license,
    references,photos,free estimates,
    also buy houses to refurbish:
    http://www.renewhouse4u.com.
    Mobile:410-978-7981.
    Thanks.

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

 
%d bloggers like this: