Geeks With Blogs
Boy Meets 'Hello World' Blogging the journey from College Grad to .NET Developer

Ok, I admit, I didn't know what ThreadStatic was before today. I'm going to chalk it up to the fact that I don't deal (or, at least, hadn't dealt up until recently) with multi-threaded situations.

 

This all came when, partially by the fact that I am not liking the conclusions I drew on this post, I have started to look more at a static method. While revisiting Udi & Ayende's examples, I took a deeper look and noticed that there might be problems with how their code might work in multi-threaded situations.

As a quick recap, In both their examples, a message handler (service-layer code) would register what should be the response they should give depending on what the domain object tells them to do The actual possible events are placed in a static class that allows the service-layer the ablity to plug in what response it wants. Code below was from Udi's post...

 

  53:  public static class FailureEvents
  54:  {
  55:      public static event EventHandler GameReportedLost;
  56:      public static void RaiseGameReportedLostEvent()
  57:      {
  58:           if (GameReportedLost != null)
  59:               GameReportedLost(null, null);
  60:      }
  61:   
  62:      public static event EventHandler CartIsFull;
  63:      public static void RaiseCartIsFullEvent()
  64:      {
  65:           if (CartIsFull != null)
  66:               CartIsFull(null, null);
  67:      }
  68:   
  69:      public static event EventHandler MaxNumberOfSameGamePerCartReached;
  70:      public static void RaiseMaxNumberOfSameGamePerCartReachedEvent()
  71:      {
  72:           if (MaxNumberOfSameGamePerCartReached != null)
  73:               MaxNumberOfSameGamePerCartReached(null, null);
  74:      }
  75:  }

 

 

So, Udi is using .NET events to allow the service layer to register what should be done (Ayende's solution, while this specific part of the class is not posted in his response, used delegates instead). However, because these are static instances, it is completely possible for a handler to register itself, then have it's thread yield while another thread goes through the entire process, at which point two handlers will be registered to the event.

I created a simple app to demonstrate and found both would not work, given the code that I had seen. I sent an e-mail to Udi, who was very pleasent in his response. In the main course of his reply...

 

The solution is to combine what Ayende said with defining the list as thread
static (using the [ThreadStatic] attribute).

 

The ThreadStaticAttribute, when placed on fields, will ensure that each thread has it's own instance of the field. This will solve the problem in multi-threaded situations, since if a separate thread tries to access the field while another was working with it, it will be getting it's own version to work with. Attribute cannot be used on events, just fields, so the event solution would not work. To stick with events, as Udi explained, you would implement something as Ayende posted in the comment of Udi's post, where you make a custom implementation of the register/unregister properties that will add the event elsewhere (and of course use ThreadStatic on this new list.

For overriding, you do something like this:

List<WeakReference> gameRentalsEvents; 

event EventHandler GameRental
{
    add { gameRentalEvents.Add(value); }
    remove { gameRentalEvents.Remove(value); }
}

 

Ayende's solution in his blog post was to use delegates, and so long as you have ThreadStatic, this would work as well. As the delegates would be fields, they could use the ThreadStatic property, and in addition would probably be a lot smaller (at perhaps one line of code in the static class).

A final note on ThreadStatic, as I found by a quick google where I found a Scott Hanselman blog post, is that there are a few things to watch out for when using it. Read his post in full, but here are the tidbits...

First off, there is the fact that in a situation like in ASP.NET, or any place where you are using worker threads, a thread might be reused at a later point, which means it might still have the value leftover. So, you might find yourself in a position where you are expecting a field in a static class with ThreadStatic to be default, but really it has some leftover value. In the delegate case, this shouldn't be a problem, since you are just overwriting your fields the next time around anyway. But it could technically be considered a minor memory leak (the delegate on the static class is still alive and well, even though it will not be utilized).

 

The second is the nature of initialization for fields marked with ThreadStatic. The docs provides...

Do not specify initial values for fields marked with ThreadStaticAttribute, because such initialization occurs only once, when the class constructor executes, and therefore affects only one thread. If you do not specify an initial value, you can rely on the field being initialized to its default value if it is a value type, or to a null reference (Nothing in Visual Basic) if it is a reference type.

In other words, this class...

public class MyClass
{
        [ThreadStatic]
        public static string myString = "test";
}

 

will behave differently on different threads. If I'm reading it right, the first thread that uses it will have "test" initialized correctly, but all the rest will be null (but don't quote me on that). It's better off to just leave the field without a default initializer, and always assume that it will start with the default value.

Posted on Friday, June 20, 2008 6:05 AM | Back to top


Comments on this post: ThreadStatic! Of course!

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © mhildreth | Powered by: GeeksWithBlogs.net