{"id":5579,"date":"2013-04-18T16:07:53","date_gmt":"2013-04-18T16:07:53","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/subterranean-il-threadlocal-revisited\/"},"modified":"2021-04-29T15:30:53","modified_gmt":"2021-04-29T15:30:53","slug":"subterranean-il-threadlocal-revisited","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/blogs\/subterranean-il-threadlocal-revisited\/","title":{"rendered":"Subterranean IL: ThreadLocal revisited"},"content":{"rendered":"<p>Last year, I looked at the <a href=\"https:\/\/www.simple-talk.com\/blogs\/2012\/05\/03\/subterranean-il-the-threadlocal-type\/\"><code>ThreadLocal<\/code><\/a> type as it exists in .NET 4. In .NET 4.5, this type has been completely rewritten. In this post, I&#8217;ll be looking at how the new <code>ThreadLocal<\/code> works in .NET 4.5. I won&#8217;t be looking at all the implementation details, but concentrating on how this type works. Again, it&#8217;s recommended you have the type open in a decompiler.<\/p>\n<h4>No More Generics!<\/h4>\n<p>The most obvious change is the lack of generic classes &#8211; it no longer uses generic instantiations to store individual thread static variables. Instead, it uses a design similar to that of <a href=\"https:\/\/www.simple-talk.com\/blogs\/2012\/03\/26\/inside-the-concurrent-collections-concurrentbag\/\"><code>ConcurrentBag<\/code><\/a> &#8211; an array of values held in a thread static array, with each instance of <code>ThreadLocal<\/code> being assigned its own index into that array, and linked lists between the items in each thread static array to allow access from any thread.<\/p>\n<p>The important variables here are the thread static <code>ts_slotArray<\/code>, <code>m_idComplement<\/code> and <code>m_linkedSlot<\/code>. Each thread has its own <code>ts_slotArray<\/code> instance, and each instance of <code>ThreadLocal<\/code> has its own slot index into those arrays as <code>m_idComplement<\/code> (I&#8217;m ignoring the fact that <code>ThreadLocal<\/code> is generic for now; each generic instantiation of <code>ThreadLocal<\/code> has its own static variables independant from any other). The list of all values stored in each instance is accessible through the linked list accessible from <code>m_linkedSlot<\/code>.<\/p>\n<p>However, these extra links between arrays mean that the value to be stored can&#8217;t be put straight into <code>ts_slotArray<\/code>, you need an extra type to provide these links. This is where the <code>LinkedSlot<\/code> type comes in &#8211; it provides a <code>Next<\/code> and <code>Previous<\/code> fields to link between slots in different arrays. This graph indicates how these different fields interact &#8211; the arrows represent the <code>Next<\/code> and <code>Previous<\/code> references between slots:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/blogbits\/simon.cooper\/ThreadLocal45.png\" alt=\"ThreadLocal45.png\" \/><\/p>\n<p>Note that the instance of <code>LinkedSlot<\/code> directly referenced by the <code>m_linkedSlot<\/code> field is an empty instance that is not stored in any array; it exists only to be the target of another slot&#8217;s <code>Previous<\/code> field, and simplifies the logic in the other methods.<\/p>\n<h4>Setting values<\/h4>\n<p>Each instance of <code>ThreadLocal<\/code> is assigned a unique index by the <code>IdManager<\/code> class when it is created. When a thread first sets a value in an instance of <code>ThreadLocal<\/code>, the following happens in <code>SetValueSlow<\/code>:<\/p>\n<ol>\n<li>If the slot array hasn&#8217;t been assigned for this thread (ie this is the first time this thread has accessed any instance of <code>ThreadLocal<\/code>), it creates a new array to hold enough items for this instance&#8217;s slot index.<\/li>\n<li>If the array isn&#8217;t big enough for this instance&#8217;s slot index, it is resized so it is, and all the containing <code>LinkedSlot<\/code>s are updated to point to the new array (in the <code>GrowTable<\/code> method).<\/li>\n<li><code>CreateLinkedSlot<\/code> is called to create a new <code>LinkedSlot<\/code> instance and store it in the array at the instance&#8217;s slot index. It also adds it to the head of the linked list pointed to by <code>m_linkedSlot<\/code> in this instance of <code>ThreadLocal<\/code>.<\/li>\n<\/ol>\n<p>Subsequently, when values are get &amp; set, it gets and sets the value at the slot index owned by the <code>ThreadLocal<\/code> being accessed, in the slot array for the accessing thread.<\/p>\n<h4>Removing and disposing of ThreadLocals<\/h4>\n<p>So that&#8217;s what happens when values are set. What about when the thread is no longer running, or the <code>ThreadLocal<\/code> is disposed? Both require values to be removed or unset in the arrays &amp; untangled in the linked lists, else any values set will just stay there, won&#8217;t be collected, and will cause a memory leak.<\/p>\n<ol>\n<li>\n<h4><code>ThreadLocal.Dispose<\/code><\/h4>\n<p>When an instance of <code>ThreadLocal<\/code> is disposed or finalized, it needs to clear the instances of <code>LinkedSlot<\/code> in all the referenced slot arrays. Fortunately, this is quite easy to do &#8211; it simply iterates through the link list defined by <code>m_linkedSlot<\/code>, and clears the entries. Finally, it returns the slot index it was using to the <code>IdManager<\/code> class to be reused when the next instance of <code>ThreadLocal<\/code> is created.<\/p>\n<\/li>\n<li>\n<h4><code>Thread exit<\/code><\/h4>\n<p>Dealing with a thread exit is harder, as there isn&#8217;t a global event that fires whenever a thread exits. Fortunately, a little-known feature of thread statics can be used to clear up the slot array belonging to a thread that has exited.<\/p>\n<\/li>\n<\/ol>\n<h4>Detecting thread exits<\/h4>\n<p>Normal static fields, once the type has been initialized, stay around until the AppDomain exits. That means that any object being referenced by a static field won&#8217;t be collected until the field is explicitly cleared.<\/p>\n<p>However, thread static fields are different. The CLR keeps track of which threads are active, and which have exited. It can link this to the various values stored in a thread static field. This means that any value set on a thread static field belonging to a thread that has exited, and that isn&#8217;t referenced by anything else, is eligible for garbage collection, and will be collected the next time the garbage collector runs.<\/p>\n<p>This feature is exploited by <code>ThreadLocal<\/code> to clear up the slot arrays of exited threads. This is primarily performed by the <code>FinalizationHelper<\/code> class, which is created and assigned to a thread static field when the slot array is first created and assigned.<\/p>\n<h4>FinalizationHelper<\/h4>\n<p>This class only exists for its finalizer. When a thread exits, the corresponding instance of <code>FinalizationHelper<\/code> assigned to the <code>ts_finalizationHelper<\/code> field becomes eligible for collection. If and when the garbage collector runs, this instance gets collected, and the finalizer is run. This finalizer removes any non-empty slots from the linked lists of active <code>ThreadLocal<\/code> instances, unless the values are needed to be kept if a call to <code>ThreadLocal.Values<\/code> is made to return all the values ever set on that instance.<\/p>\n<h4>Conclusion<\/h4>\n<p>So there we are; the upgraded <code>ThreadLocal<\/code>. It&#8217;s an improvement on the old version, in that it allows access to all the values ever set on an instance of <code>ThreadLocal<\/code>, it doesn&#8217;t fallback on the thread local data store, and it doesn&#8217;t pollute the namespace with thousands of generic instances of holder classes. Much better!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last year, I looked at the ThreadLocal type as it exists in .NET 4. In .NET 4.5, this type has been completely rewritten. In this post, I&#8217;ll be looking at how the new ThreadLocal works in .NET 4.5. I won&#8217;t be looking at all the implementation details, but concentrating on how this type works. Again,&#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-5579","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\/5579","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=5579"}],"version-history":[{"count":7,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/5579\/revisions"}],"predecessor-version":[{"id":75601,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/5579\/revisions\/75601"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=5579"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=5579"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=5579"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=5579"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}