My and threading (TheadStatic, ThreadSafeObjectProvider)

Posted Fri, Apr 14 2006 1:50 by bill
Yesterday I got an interesting email from Tobin Titus about an issue with threading and My.Forms, so I thought I'd delve into the depths of My and threading, in particular the ThreadStatic attribute and ThreadSafeObjectProvider (especially considering google couldn't find those two in the one search !)
 
Okay, My.Forms and other properties of My are thread static, but what exactly does that mean ?
 
Thread static as the name might imply, means that the field is thread specific. Each thread will have it's own copy of the field.  This is incredibly useful when dealing with transactional types of data, and it's also useful with workflows etc.

In .NET, you make a field thread static by applying, the ThreadStatic attribute to it. e.g.
   <ThreadStatic>Private m_Context as New Object
or at least that's the theory.  However it isn't that simple.  If you tried using a thread static field as shown, you'd find that the field would only be initialized on the thread that called the instance constructor; for all other threads it would be null.  So the pattern you should use is a property with a private backing field. The property should initialize the field if needed. This ensures correct initialization for every thread. You don't have to worry about locks, as the backing field is thread specific.  So the simplest form of adding a thread safe and specific variable is as follows:

   <ThreadStatic>Private m_Context as Object
   
   Public ReadOnly Property MyContext as Object 
      Get
          If  m_Context Is Nothing Then m_Context = New Object
          Return m_Context
      End Get
   End Property
 
But I stress that's the simplest form.  When dealing with remoting, class libraries running on web services etc, you might decide to use the http context to provide that "per transaction" kind of storage.  At this point it really does get to be a lot of work for what should be a simple thing……  Enter My to the rescue
 
As part of the My framework, the VB.NET 2005 compiler generates an ThreadSafeObjectProvider(Of T) class for you.  This is used throughout the My Application framework.  It's generated with your application because the actual context it uses is based on the type of application you are building, be it a UI app (console or winforms), a class library or  a web app.  VB deals with all the complexities of the plumbing.  To use the ThreadSafeObjectProvider class you write code like :
 
Private  m_MyContext As  New  My.MyProject.ThreadSafeObjectProvider(Of  Object)
 
Private  ReadOnly  Property  MyContext () As Object
   Get
      Return  m_MyContext.GetInstance
    End  Get
End  Property
 
 
And there you have a nice thread safe, thread specific storage.  I used "Object" above, but you can make it anything you like.  I used this earlier today to provide  a temporary cache across methods inside a component. The cache had to be thread specific as it was being used in a sorting routine, and we definitely didn't want to be doing locks during the sort.  Of course, astute readers of my blog are probably saying, "hey wouldn't captures and anonymous delegates given you the same effect", and the answer would have been probably yes ;)  albeit at the expense of code reuse.
 
Okay, so that's the good news. The bad news is the ThreadSafeObjectProvider is marked as not browsable, so you won't get intellisense when you go to add it to your code.  That's a real pain.  In fact still having to write that backing field and property declaration is a pain, so I created my own snippet that will give you the above pattern, and assigned it the shortcut of "ThreadStatic".  It's a good memory trigger that should I go to write ThreadStatic and hit the tab key, I'll be blessed with a nice safe wrapper rather than what can be risky business if done badly.
 
 
 
Okay, so we've looked a little at ThreadStatic and ThreadSafeObjectProvider. Now onto My and in particular Tobin's blog entry.
 
The my application framework generates classes for the My.<dot> experience. My.Application is actually an instance of the MyApplication class. Likewise My.Forms is an instance of the MyForms class.  These instances are actually exposed via properties in the MyProject module. And yes they are exposed using the very same pattern as I showed above and that's in my ThreadStatic snippet.
So what's that mean ? Well it means that My.Forms is thread specific.  One could argue they are being a bit overzealous there, but considering the very nature of Windows.Forms is STA threaded, and that you have to marshal over to the UI thread when trying to set properties of controls, then it's probably more consistent being thread specific. 
 
But how do you deal with Forms across different threads ?  Tobin put forward one workaround of using the open forms collection and passing in a string.  I always see flashing red lights around string literals in code that isn't automatically generated, so I would not suggest you do that.  Instead you can easily create a shared property that exposes what the MyForms main thread's instance.  Using a partial class for your MyApplication, just hook into the application startup, and store a reference to My.Forms, then expose that:
 
Partial  Friend  Class  MyApplication
   Private  Shared  m_forms  As  MyForms
   Public  ReadOnly  Property  SharedForms()  As  MyForms
      Get
          Return  m_forms
      End  Get
    End  Property
 
     Private  Sub  MyApplication_Startup(ByVal  sender  As  Object ByVal  e  As  Microsoft.VisualBasic.ApplicationServices.StartupEventArgs)  Handles  Me.Startup
          m_forms  =  My.Forms
     End  Sub
End  Class
 
 
Now throughout your code you could access My.Application.SharedForms.Form1 etc, and that wouldn't be thread specific.  Of course, in the "problem" code Tobin showed, that would just mean you were in fact dealing with the same form, but on the wrong thread, and so you'd get a threading exception.   But life odes get a little simpler because you'd now be able to test if Invoke was required. Using the sample code from Tobin's blog, the Ui thread safe code becomes:
 
Public  Sub  WaitForData(ByVal  strMessage  As  String)
   Dim  frm  As  Form2  =  My.Application.SharedForms.Form2
   If  frm.InvokeRequired  Then
       frm.Invoke(New  UpdateTextHandler(AddressOf  WaitForData),  strMessage)
       Return
   EndIf
   'if here we're on the Ui thread
   frm.TextBox1.Text  &=  strMessage
End  Sub
 
 
So there we've used the Shared forms to see if invoke is required, and if so we call Control.Invoke back to the same method.


Filed under: ,

Comments

# re: My and threading (TheadStatic, ThreadSafeObjectProvider)

Friday, April 28, 2006 4:33 PM by Tobin Titus

Nicely done, Bill.

# Custom ThreadSafeObjectProvider in C# &laquo; Net Hacks

Wednesday, September 06, 2006 11:04 PM by Custom ThreadSafeObjectProvider in C# « Net Hacks

# Custom ThreadSafeObjectProvider in C# &laquo; Only 4 .NET Developers

Thursday, September 14, 2006 3:26 PM by Custom ThreadSafeObjectProvider in C# « Only 4 .NET Developers

# What is the mysterious ThreadSafeObjectProvider

Sunday, October 09, 2011 3:18 PM by What is the mysterious ThreadSafeObjectProvider

Pingback from  What is the mysterious ThreadSafeObjectProvider