{"id":3541,"date":"2012-05-03T12:11:00","date_gmt":"2012-05-03T12:11:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/subterranean-il-the-threadlocal-type\/"},"modified":"2021-04-29T15:30:53","modified_gmt":"2021-04-29T15:30:53","slug":"subterranean-il-the-threadlocal-type","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/blogs\/subterranean-il-the-threadlocal-type\/","title":{"rendered":"Subterranean IL: The ThreadLocal type"},"content":{"rendered":"<p>I came across <code>ThreadLocal&lt;T&gt;<\/code> while I was researching <code>ConcurrentBag<\/code>. To look at it, it doesn&#8217;t really make much sense. What&#8217;s all those extra <code>Cn<\/code> classes doing in there? Why is there a <code>GenericHolder&lt;T,U,V,W&gt;<\/code> class? What&#8217;s going on? However, digging deeper, it&#8217;s a rather ingenious solution to a tricky problem.<\/p>\n<h4>Thread statics<\/h4>\n<p>Declaring that a variable is thread static, that is, values assigned and read from the field is specific to the thread doing the reading, is quite easy in .NET:<\/p>\n<pre>[ThreadStatic]\nprivate static string s_ThreadStaticField;<\/pre>\n<p><code>ThreadStaticAttribute<\/code> is not a <a href=\"https:\/\/www.simple-talk.com\/community\/blogs\/simonc\/archive\/2010\/11\/30\/95936.aspx\">pseudo-custom attribute<\/a>; it is compiled as a normal attribute, but the CLR has in-built magic, activated by that attribute, to redirect accesses to the field based on the executing thread&#8217;s identity.<\/p>\n<p><code>TheadStaticAttribute<\/code> provides a simple solution when you want to use a single field as thread-static. What if you want to create an arbitary number of thread static variables at runtime? Thread-static fields can only be declared, and are fixed, at compile time. Prior to .NET 4, you only had one solution &#8211; <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/6sby1byh.aspx\">thread local data slots<\/a>. This is a lesser-known function of <code>Thread<\/code> that has existed since .NET 1.1:<\/p>\n<pre>LocalDataStoreSlot threadSlot = Thread.AllocateNamedDataSlot(\"slot1\");\n\nstring value = \"foo\";\nThread.SetData(threadSlot, value);\n\nstring gettedValue = (string)Thread.GetData(threadSlot);<\/pre>\n<p>Each instance of <code>LocalStoreDataSlot<\/code> mediates access to a single slot, and each slot acts like a separate thread-static field.<\/p>\n<p>As you can see, using thread data slots is quite cumbersome. You need to keep track of <code>LocalDataStoreSlot<\/code> objects, it&#8217;s not obvious how instances of <code>LocalDataStoreSlot<\/code> correspond to individual thread-static variables, and it&#8217;s not type safe. It&#8217;s also relatively slow and complicated; the internal implementation consists of a whole series of classes hanging off a single thread-static field in <code>Thread<\/code> itself, using various arrays, lists, and locks for synchronization. <code>ThreadLocal&lt;T&gt;<\/code> is far simpler and easier to use.<\/p>\n<h4>ThreadLocal<\/h4>\n<p><code>ThreadLocal<\/code> provides an abstraction around thread-static fields that allows it to be used just like any other class; it can be used as a replacement for a thread-static field, it can be used in a <code>List&lt;ThreadLocal&lt;T&gt;&gt;<\/code>, you can create as many as you need at runtime. So what does it do? It can&#8217;t just have an instance-specific thread-static field, because thread-static fields have to be declared as <code>static<\/code>, and so shared between all instances of the declaring type. There&#8217;s something else going on here.<\/p>\n<p>The values stored in instances of <code>ThreadLocal&lt;T&gt;<\/code> are stored in instantiations of the <code>GenericHolder&lt;T,U,V,W&gt;<\/code> class, which contains a single <code>ThreadStatic<\/code> field (<code>s_value<\/code>) to store the actual value. This class is then instantiated with various combinations of the <code>Cn<\/code> types for generic arguments.<\/p>\n<p>In .NET, each separate instantiation of a generic type has its own static state. For example, <code>GenericHolder&lt;int,C0,C1,C2&gt;<\/code> has a completely separate <code>s_value<\/code> field to <code>GenericHolder&lt;int,C1,C14,C1&gt;<\/code>. This feature is (ab)used by <code>ThreadLocal<\/code> to emulate instance thread-static fields.<\/p>\n<p>Every time an instance of <code>ThreadLocal<\/code> is constructed, it is assigned a unique number from the static <code>s_currentTypeId<\/code> field using <code>Interlocked.Increment<\/code>, in the <code>FindNextTypeIndex<\/code> method. The hexadecimal representation of that number then defines the specific <code>Cn<\/code> types that instantiates the <code>GenericHolder<\/code> class. That instantiation is therefore &#8216;owned&#8217; by that instance of <code>ThreadLocal<\/code>.<\/p>\n<p>This gives each instance of <code>ThreadLocal<\/code> its own <code>ThreadStatic<\/code> field through a specific unique instantiation of the <code>GenericHolder<\/code> class. Although <code>GenericHolder<\/code> has four type variables, the first one is always instantiated to the type stored in the <code>ThreadLocal&lt;T&gt;<\/code>. This gives three free type variables, each of which can be instantiated to one of 16 types (<code>C0<\/code> to <code>C15<\/code>). This puts an upper limit of 4096 (163) on the number of <code>ThreadLocal&lt;T&gt;<\/code> instances that can be created for each value of T. That is, there can be a maximum of 4096 instances of <code>ThreadLocal&lt;string&gt;<\/code>, and separately a maximum of 4096 instances of <code>ThreadLocal&lt;object&gt;<\/code>, etc.<\/p>\n<p>However, there is an upper limit of 16384 enforced on the total number of <code>ThreadLocal<\/code> instances in the AppDomain. This is to stop too much memory being used by thousands of instantiations of <code>GenericHolder&lt;T,U,V,W&gt;<\/code>, as once a type is loaded into an AppDomain it cannot be unloaded, and will continue to sit there taking up memory until the AppDomain is unloaded. The total number of <code>ThreadLocal<\/code> instances created is tracked by the <code>ThreadLocalGlobalCounter<\/code> class.<\/p>\n<p>So what happens when either limit is reached? Firstly, to try and stop this limit being reached, it recycles <code>GenericHolder<\/code> type indexes of <code>ThreadLocal<\/code> instances that get disposed using the <code>s_availableIndices<\/code> concurrent stack. This allows <code>GenericHolder<\/code> instantiations of disposed <code>ThreadLocal<\/code> instances to be re-used. But if there aren&#8217;t any available instantiations, then <code>ThreadLocal<\/code> falls back on a standard thread local slot using <code>TLSHolder<\/code>. This makes it very important to dispose of your <code>ThreadLocal<\/code> instances if you&#8217;ll be using lots of them, so the type instantiations can be recycled.<\/p>\n<p>The previous way of creating arbitary thread-static variables, thread data slots, was slow, clunky, and hard to use. In comparison, <code>ThreadLocal<\/code> can be used just like any other type, and each instance appears from the outside to be a non-static thread-static variable. It does this by using the CLR type system to assign each instance of <code>ThreadLocal<\/code> its own instantiated type containing a thread-static field, and so delegating a lot of the bookkeeping that thread data slots had to do to the CLR type system itself! That&#8217;s a very clever use of the CLR type system.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I came across ThreadLocal&lt;T&gt; while I was researching ConcurrentBag. To look at it, it doesn&#8217;t really make much sense. What&#8217;s all those extra Cn classes doing in there? Why is there a GenericHolder&lt;T,U,V,W&gt; class? What&#8217;s going on? However, digging deeper, it&#8217;s a rather ingenious solution to a tricky problem. Thread statics Declaring that a variable&#8230;&hellip;<\/p>\n","protected":false},"author":186659,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538,2],"tags":[],"coauthors":[],"class_list":["post-3541","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","category-blogs"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/3541","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/186659"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=3541"}],"version-history":[{"count":2,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/3541\/revisions"}],"predecessor-version":[{"id":75602,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/3541\/revisions\/75602"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=3541"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=3541"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=3541"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=3541"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}