Thread Local Storage and Managed Threads vs O/S Threads

  • Thread starter Thread starter Chris Mullins [MVP]
  • Start date Start date
C

Chris Mullins [MVP]

I've been doing quite a bit these past few days with Thread Local Storage -
specifically using the ThreadStatic attribute.

.... but last night, I got to thinking. When .Net code is running, it's
running on a Managed Thread, not (directly) an O/S thread. There's no
guarantee made that, from timeslice to timeslice, code will actually be
running on the same O/S thread. I don't think any CLR versions swap out the
O/S thread today, but depending on the hosting model it's a possability.

To comabt this, the CLR team has added two atrributes to the Thread
namespace:
BeginThreadAffinity
EndThreadAffinity

Now, by using Thread Local Storage (either a Named or Unnamed data slot, or
simply via the ThreadStatic attribute) I absolutly have Thread Affinity. I'm
trying now to figure out if I need to use the Begin/End ThreadAffinity
methods on my processing. If so, it's.. going to be ugly. I can't really
tell, from the documentation, if this is the case. Logically, it seems like
they should be required, but given the ensuing complexity, I can't really
see it.

My Thread Local stuff is all encapsulated in a class, that looks like:

public class Context
{
[ThreadStatic()]
private static Context _current;
private string _value;

public Context(){ _current = this; }
public static Context Current
{
get { return _current; }
}

public string Value
{
get { return _value; }
set { _value = value; }
}
}

Is there a better way to accomplish this same task? I see (via Reflector)
that ASP.Net actually uses Remoting Contexts to have Context.Current work
properly. Would I be better off using a context bound object (the same way
System.Transaction works)?
 
Chris Mullins said:
I've been doing quite a bit these past few days with Thread Local Storage -
specifically using the ThreadStatic attribute.

... but last night, I got to thinking. When .Net code is running, it's
running on a Managed Thread, not (directly) an O/S thread. There's no
guarantee made that, from timeslice to timeslice, code will actually be
running on the same O/S thread. I don't think any CLR versions swap out the
O/S thread today, but depending on the hosting model it's a possability.

To comabt this, the CLR team has added two atrributes to the Thread
namespace:
BeginThreadAffinity
EndThreadAffinity

Now, by using Thread Local Storage (either a Named or Unnamed data slot, or
simply via the ThreadStatic attribute) I absolutly have Thread Affinity.

How sure are you of that? I would expect that in order to maintain the
semantics of ThreadStatic, that if the managed thread changes which OS
thread it's running on (and I don't know if that's actually ever been
implemented in a production CLR - I know it was part of the .NET 2.0
effort for SQL Server 2005 integration, with fibers etc, but I thought
it had been dropped) it would "move" all the ThreadStatic data over to
the other thread.

Indeed, I'm sure I read something to that effect before 2.0 was
released. Blowed if I can find it now though, I'm afraid...
I suspect Joe Duffy may be the best person to ask...
 
Jon Skeet said:
How sure are you of that?

Well, I'm sure I have (at least) Managed Thread affinity. As to having
Unmanaged thread affinity, I'm not sure.

Some of the methods on Thread, such as AllocateDataSlot, are marked
(according to Reflector) with "[ExternalThreading=True]".

The internals of the various TLS methods (AllocateDataSlot, etc) are just
managing a hashtable of slots. There's nothing I see that ties the hashtable
itself to the thread - which (to me) leave the question unanswered.
I would expect that in order to maintain the
semantics of ThreadStatic, that if the managed thread changes which OS
thread it's running on (and I don't know if that's actually ever been
implemented in a production CLR - I know it was part of the .NET 2.0
effort for SQL Server 2005 integration, with fibers etc, but I thought
it had been dropped) it would "move" all the ThreadStatic data over to
the other thread.

I agree - this should be the case. None of the code that I can see via
Reflector does this though. Hopefullly it's an "under the hood" type of
thing. I can't decide if this is just a case of me knowing "just enough" to
cause worry, but "not enough" to know it's not an issue.

I have read in Joe Duffy's blog that fiber support was removed at the 11th
hour.
Indeed, I'm sure I read something to that effect before 2.0 was
released. Blowed if I can find it now though, I'm afraid...
I suspect Joe Duffy may be the best person to ask...


I sent Joe an email - he's been great in the past about answering questions.
Hopefully he'll respond. I also sent it to Richter, who has also been great
in the past about answering obscure questions..
 
Chris Mullins said:
I sent Joe an email - he's been great in the past about answering questions.
Hopefully he'll respond. I also sent it to Richter, who has also been great
in the past about answering obscure questions..

Cool. Do let us know what the answer is :)
 
Chris Mullins said:
Jon Skeet said:
How sure are you of that?

Well, I'm sure I have (at least) Managed Thread affinity. As to having Unmanaged thread
affinity, I'm not sure.

Some of the methods on Thread, such as AllocateDataSlot, are marked (according to
Reflector) with "[ExternalThreading=True]".

The internals of the various TLS methods (AllocateDataSlot, etc) are just managing a
hashtable of slots. There's nothing I see that ties the hashtable itself to the thread -
which (to me) leave the question unanswered.
I would expect that in order to maintain the
semantics of ThreadStatic, that if the managed thread changes which OS
thread it's running on (and I don't know if that's actually ever been
implemented in a production CLR - I know it was part of the .NET 2.0
effort for SQL Server 2005 integration, with fibers etc, but I thought
it had been dropped) it would "move" all the ThreadStatic data over to
the other thread.

I agree - this should be the case. None of the code that I can see via Reflector does this
though. Hopefullly it's an "under the hood" type of thing. I can't decide if this is just
a case of me knowing "just enough" to cause worry, but "not enough" to know it's not an
issue.

I have read in Joe Duffy's blog that fiber support was removed at the 11th hour.
Indeed, I'm sure I read something to that effect before 2.0 was
released. Blowed if I can find it now though, I'm afraid...
I suspect Joe Duffy may be the best person to ask...


I sent Joe an email - he's been great in the past about answering questions. Hopefully
he'll respond. I also sent it to Richter, who has also been great in the past about
answering obscure questions..


I've done some research (using V2) on this some time ago using unmanaged hosting and using
fibers, what I found out is that , managed TLS is stored in FLS when fibers are used (that
is, a managed thread mapped on a fiber). FLS includes stuff like ThreadStaticAttribute and
Thread.GetData and Thread.SetData. I remember "FiberSwitch" took care of moving FLS data
when switching fibers. but I got stuck in regression and stopped with this all, when I
found-out that the current CLR release did not officially support fibers as (partly)
documented and was not completely implemented and tested.
It's really something we shouldn't rely on for production code. All you can do for now, is
like the SQL team has done, take this all away from the CLR and handle it in the unmanaged
host.
Now I heard that the designer of this stuff left the CLR team, I doubt if we ever going to
see a fiber based CLR. in the future

Willy.
 
I got a response from both Joe Duffy & Jeff Richter for this.

Both of them agreed it's the job of the CLR to deal with this, and that if
anyone ever does actually implement a fiber mode version, it's up to them to
get it right. In the meantime, thread local storage is perfectly safe to
use, and there's no need to use the Begin/EndThreadAffinity markers.
 
Back
Top