{"id":55988,"date":"2009-06-24T18:39:45","date_gmt":"2009-06-24T18:39:45","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/pfxteam\/2009\/06\/24\/dont-dispose-of-objects-that-you-dont-own\/"},"modified":"2009-06-24T18:39:45","modified_gmt":"2009-06-24T18:39:45","slug":"dont-dispose-of-objects-that-you-dont-own","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/dont-dispose-of-objects-that-you-dont-own\/","title":{"rendered":"Don\u2019t dispose of objects that you don\u2019t own"},"content":{"rendered":"<p>In concurrent programs, race conditions are a fact of life but they aren\u2019t all bad.&#160; Sometimes, race conditions are benign, as is often the case with lazy initialization.&#160; <\/p>\n<p>The problem with racing to set a value, however, is that it can result in multiple objects being instantiated when only one is needed.&#160; Take the LazyInitializer class that shipped in Visual Studio 2010 Beta 1, for example.&#160; The method <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/dd642284(VS.100).aspx\">EnsureInitialized(ref T target, Func&lt;T&gt; valueFactory)<\/a> accepts a ByRef value and a function that produces a value.&#160; If <em>target<\/em> is null, EnsureInitialized will execute <em>valueFactory<\/em> and set target to the return value.&#160; If multiple threads happen to overlap calls to EnsureInitialized, which is likely to be a rare occurrence, these threads may both initially see target as null and then execute valueFactory.&#160; One thread will win the race and will get to set <em>target<\/em>.&#160; <\/p>\n<p>In Beta 1, we thought we\u2019d be really smart by disposing of the objects that were created by threads that lost the race, if they implemented IDisposable.&#160; Turns out that\u2019s a pretty bad thing to do.&#160; With lazy initialization, we assumed that most of time valueFactory would be creating a new value but that isn\u2019t always the case.&#160; It\u2019s quite possible that a valueFactory could return an object that has already been created, in which case, we\u2019d be disposing of an object we didn\u2019t own.&#160; <\/p>\n<p>We\u2019re making a couple of changes in the Parallel Extensions to ensure that we generally don\u2019t dispose of object we aren\u2019t sure we own and, moving forward, any new APIs that do eagerly instantiate objects that might not be used will not dispose of said objects.&#160; <\/p>\n<p>Now you might say, \u201cwhy?&#160; Ninety-percent of the time I <em>am<\/em> creating a new object with my value factory and it might be a really heavy object like a file or wait handle!\u201d&#160; We hear you, but typically, once an object is disposed, there is no bringing it back and so by disposing of these objects we don\u2019t allow anyone to opt out of that behavior if need be.&#160; If we don\u2019t dispose, the GC will still cleanup your unused objects and if you really need to dispose of an object manually, there is a work around, i.e.<\/p>\n<pre class=\"csharpcode\">ManualResetEvent theEvent = <span class=\"kwrd\">null<\/span>;\nManualResetEvent tmpEvent;\nLazyInitializer.EnsureInitialized(<span class=\"kwrd\">ref<\/span> theEvent, \n     () =&gt; { <span class=\"kwrd\">return<\/span> tmpEvent = <span class=\"kwrd\">new<\/span> ManualResetEvent(<span class=\"kwrd\">false<\/span>); });\n<span class=\"kwrd\">if<\/span> (tmpEvent != theEvent) tmpEvent.Close();<\/pre>\n<p>In fact, you could easily create a small wrapper function to do the work for you, i.e.<\/p>\n<pre class=\"csharpcode\"><span class=\"kwrd\">public<\/span> <span class=\"kwrd\">static<\/span> T EnsureInitializedWithDispose&lt;T&gt;(<span class=\"kwrd\">ref<\/span> T target, Func&lt;T&gt; function) \n    <span class=\"kwrd\">where<\/span> T : <span class=\"kwrd\">class<\/span>, IDisposable\n{\n    T tmp = <span class=\"kwrd\">default<\/span>(T);\n    T actual = LazyInitializer.EnsureInitialized(<span class=\"kwrd\">ref<\/span> target, () =&gt; tmp = function());\n    <span class=\"kwrd\">if<\/span> (actual != tmp) ((IDisposable)tmp).Dispose();\n    <span class=\"kwrd\">return<\/span> actual;\n}<\/pre>\n<p>.csharpcode, .csharpcode pre\n{\n\tfont-size: small;\n\tcolor: black;\n\tfont-family: consolas, &#8220;Courier New&#8221;, courier, monospace;\n\tbackground-color: #ffffff;\n\t\/*white-space: pre;*\/\n}\n.csharpcode pre { margin: 0em; }\n.csharpcode .rem { color: #008000; }\n.csharpcode .kwrd { color: #0000ff; }\n.csharpcode .str { color: #006080; }\n.csharpcode .op { color: #0000c0; }\n.csharpcode .preproc { color: #cc6633; }\n.csharpcode .asp { background-color: #ffff00; }\n.csharpcode .html { color: #800000; }\n.csharpcode .attr { color: #ff0000; }\n.csharpcode .alt \n{\n\tbackground-color: #f4f4f4;\n\twidth: 100%;\n\tmargin: 0em;\n}\n.csharpcode .lnum { color: #606060; }<\/p>\n<p>And the issue isn\u2019t just about race conditions.&#160; In general, we should never dispose of an object we didn\u2019t explicitly create.&#160; BlockingCollection&lt;T&gt; in Beta 1, for example, will dispose of it\u2019s underlying collection if the BlockingCollection&lt;T&gt; itself is disposed.&#160; Again, this is bad news if you only were using the BlockingCollection&lt;T&gt; as a temporary wrapper.&#160; In future releases of Visual Studio 2010, this will be corrected. <\/p>\n<p>So when using these APIs, and any other API that may consume or create an IDisposable object, think about what that API is doing with the object and if you need to clean up resources manually.&#160; If you\u2019re not sure, the finalizer should take care of most of your problems.&#160; In the rare situations where immediate cleanup is important, make sure you keep track of the objects and dispose of them properly.&#160; Also, when designing your own libraries, don\u2019t dispose of objects you don\u2019t own!\n.csharpcode, .csharpcode pre\n{\n\tfont-size: small;\n\tcolor: black;\n\tfont-family: consolas, &#8220;Courier New&#8221;, courier, monospace;\n\tbackground-color: #ffffff;\n\t\/*white-space: pre;*\/\n}\n.csharpcode pre { margin: 0em; }\n.csharpcode .rem { color: #008000; }\n.csharpcode .kwrd { color: #0000ff; }\n.csharpcode .str { color: #006080; }\n.csharpcode .op { color: #0000c0; }\n.csharpcode .preproc { color: #cc6633; }\n.csharpcode .asp { background-color: #ffff00; }\n.csharpcode .html { color: #800000; }\n.csharpcode .attr { color: #ff0000; }\n.csharpcode .alt \n{\n\tbackground-color: #f4f4f4;\n\twidth: 100%;\n\tmargin: 0em;\n}\n.csharpcode .lnum { color: #606060; }<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In concurrent programs, race conditions are a fact of life but they aren\u2019t all bad.&#160; Sometimes, race conditions are benign, as is often the case with lazy initialization.&#160; The problem with racing to set a value, however, is that it can result in multiple objects being instantiated when only one is needed.&#160; Take the LazyInitializer [&hellip;]<\/p>\n","protected":false},"author":486,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7908],"tags":[],"class_list":["post-55988","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pfxteam"],"acf":[],"blog_post_summary":"<p>In concurrent programs, race conditions are a fact of life but they aren\u2019t all bad.&#160; Sometimes, race conditions are benign, as is often the case with lazy initialization.&#160; The problem with racing to set a value, however, is that it can result in multiple objects being instantiated when only one is needed.&#160; Take the LazyInitializer [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/55988","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/486"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=55988"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/55988\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=55988"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=55988"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=55988"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}