<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>Multi-Threading</title>
        <link>http://www.mostlylucid.net/category/16.aspx</link>
        <description>Multi-Threading</description>
        <language>en-US</language>
        <copyright>Scott Galloway</copyright>
        <generator>Subtext Version 2.1.0.5</generator>
        <item>
            <title>WPF for the Web guy&amp;hellip;a story of pain, despair and learning</title>
            <link>http://mostlylucid.net/archive/2010/01/20/1332.aspx</link>
            <description>&lt;p&gt;Well, OK I’m over dramatizing it a tad :) As you may have noticed from my &lt;a href="http://mostlylucid.net/archive/2010/01/07/1331.aspx"&gt;last post&lt;/a&gt; I’ve started working of some stuff which is outside my comfort zone. I recently joined a company called &lt;a href="http://blog.cozwecan.com"&gt;cozwecan&lt;/a&gt;,working for a chap named &lt;a href="http://twitter.com/robertthegrey"&gt;@RobertTheGrey&lt;/a&gt;, the first project we’re working on is a photo sales site…you know kind of like Getty Images / Smugmug / Flickr except for direct photographer-customer sales. As the only &lt;a href="http://blog.cozwecan.com/2010/01/year-and-team-members.html"&gt;full-time developer&lt;/a&gt; (so far!)  I’ve been tasked with building the vast majority of the applications (be they web, desktop, etc…) which we need for the business to work.&lt;/p&gt;  &lt;p&gt;Obviously one of the most critical bits for an e-commerce site is stuff to sell! In our case this is a stock of really high quality photographs taken by professional photographers around the world. First question; how do we get these images on the site, and how do we let the photographers add information to their photographs to let them be found by folks who want to buy them? Well, that’s the first problem I’ve been asked to solve!&lt;/p&gt;  &lt;p&gt;When working on the requirements, it quickly became clear that this had to be a desktop app, it needed to allow operations on multi-megabyte photographs, needed to allow ‘tagging’ offline. Especially during initial loading, there’s 10-100s of thousands of images getting worked on…forcing this to be online adds a nasty lag and makes the task a pain in the butt to complete. Above all, it needed to be reliable!   &lt;br /&gt;Now, in my dev head this led to a number of decisions about the features the app would need to support:&lt;/p&gt;  &lt;p&gt;1. Intuitive, responsive UI; the users are not necessarily computer-savvy, need to use obvious UI metaphors and make it fast enough to be pleasant to use.   &lt;br /&gt;2. Needs to do some offline image processing; we’re planning on hosting this on the cloud….CPU time costs cash :)    &lt;br /&gt;3. Should work offline    &lt;br /&gt;4. Needs to be built around reliable upload of multi-meg files (across potentially tiny connection bandwidths).    &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;So, these are the basic needs…technically this leads me to some technology choices:&lt;/p&gt;  &lt;p&gt;1. Multi-threading / concurrency (as with any real desktop app) is key…as is a decent Desktop technology…   &lt;br /&gt;2. See above, we need to ‘watch’ for new files arriving, make thumbnails transparently etc…    &lt;br /&gt;3. So, it needs some sort of persistence…along with other non-core app requirements (e.g. tagging) we’ll likely need a little, lightweight DB.    &lt;br /&gt;4. Needs ‘block’ based uploads with retry / verification of uploaded items…&lt;/p&gt;  &lt;p&gt;Luckily I’ve been a dev for quite a while and had at least some idea where to start…the biggest challenge would be learning!    &lt;br /&gt;Firstly, the obvious desktop platform de jour is WPF…this is in essence the current replacement for WinForms, it’s VERY customizable but has a somewhat infamously steep learning curve. I’ve spent a bit of cash on &lt;a href="http://www.amazon.co.uk/Pro-WPF-2008-Presentation-Foundation/dp/1590599551/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1264019165&amp;amp;sr=8-1"&gt;books&lt;/a&gt; on &lt;a href="http://www.amazon.co.uk/WPF-Action-Visual-Studio-2008/dp/1933988223/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1264019184&amp;amp;sr=8-1"&gt;WPF&lt;/a&gt;, followed all the PDC presentations, podcasts etc…on the subject matter. After 3 weeks I’m finally getting comfortable with it…    &lt;br /&gt;Second, I needed a DB…needed to be lightweight, needed to support LINQ (what, I like LINQ :)), needed to support some sort of ORM technology.  &lt;br /&gt;The most obvious choice was &lt;a href="http://www.microsoft.com/Sqlserver/2008/en/us/compact.aspx"&gt;SQL Server Compact Edition&lt;/a&gt;, a kind of cut down SQL server which is great for desktop apps…however…I could not get it working! Turns out it’s really sensitive to the versions of various installed components. This was a red light for me…I needed the DB to be as stand-alone as possible! That left one obvious choice:    &lt;br /&gt;SQLite, from the website:&lt;/p&gt;  &lt;p&gt;‘SQLite is a software library that implements a &lt;a href="http://www.sqlite.org/selfcontained.html"&gt;self-contained&lt;/a&gt;, &lt;a href="http://www.sqlite.org/serverless.html"&gt;serverless&lt;/a&gt;, &lt;a href="http://www.sqlite.org/zeroconf.html"&gt;zero-configuration&lt;/a&gt;, &lt;a href="http://www.sqlite.org/transactional.html"&gt;transactional&lt;/a&gt; SQL database engine. SQLite is the &lt;a href="http://www.sqlite.org/mostdeployed.html"&gt;most widely deployed&lt;/a&gt; SQL database engine in the world. The source code for SQLite is in the &lt;a href="http://www.sqlite.org/copyright.html"&gt;public domain&lt;/a&gt;.’&lt;/p&gt;  &lt;p&gt;Perfect! For .NET support, I used the &lt;a href="http://sqlite.phxsoftware.com/"&gt;SQLite ADO.NET provider&lt;/a&gt; (there is a &lt;a href="http://code.google.com/p/csharp-sqlite/"&gt;C# only port of SQLite&lt;/a&gt;, but it’s slower and not needed for my scenario. Deployment is literally including a reference and creating a file…now it does have one pretty severe limitation which I’ll cover later :) &lt;/p&gt;  &lt;p&gt;My ORM choices were &lt;a href="https://www.hibernate.org/343.html"&gt;nHibernate&lt;/a&gt; or EF…there being support for SQLite in both of these platforms.     &lt;br /&gt;Now, I have used nHibernate for a &lt;a href="http://www.trainyourbusinessbrain.com/business-brain-training/"&gt;recent project&lt;/a&gt; (disclaimer, I left fairly early in the project :))  and one of the things which annoyed me was the large number of dependencies, and the seeming fragility across versions of these dependencies. For a low impact desktop app, this was just too large a footprint and too big a risk. So I had to count it out.     &lt;br /&gt;This left me with one choice…&lt;a href="http://en.wikipedia.org/wiki/ADO.NET_Entity_Framework"&gt;Entity Framework&lt;/a&gt;. Now, this wasn’t an easy choice…I have used EF in the past (tinkered with it) and found it a painful experience…(others have too which &lt;a href="http://efvote.wufoo.com/forms/ado-net-entity-framework-vote-of-no-confidence/"&gt;led to this&lt;/a&gt;). Now, I’m not getting into the politics behind MS choice to push EF (and yes, it was a political choice), but V1 is fairly buggy, and for me at least fairly unnatural. This led to my second learning ‘opportunity’…Master Entity Framework! As I write this, it’s literally 2 hours since I worked out my last bit of EF pain…which led to this model:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.mostlylucid.net/Images/WPFfortheWebguyastoryofpaindespairandlea_126C4/Capture.jpg"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="Capture" border="0" alt="Capture" src="http://www.mostlylucid.net/Images/WPFfortheWebguyastoryofpaindespairandlea_126C4/Capture_thumb.jpg" width="670" height="429" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Looks simple…well, yeah…but it’s taken me AGES to get to this…I know SQL really well, C# REALLY well, but the mix of obscure concepts, poor documentation and obfuscated error messages makes working / learning EF way too hard! EF 4 (in VS 2010 / .NET 4) improves this…and it can’t come soon enough!&lt;/p&gt;  &lt;p&gt;So, that’s worked out…I hope :) &lt;/p&gt;  &lt;p&gt;So, I mentioned previously that SQLite has a bit of an issue…it doesn’t really like concurrency. Well, that’s an overstatement…it is a multi-read, single write system. Once you realize it’s an issue it’s fairly easy to solve. I use this pattern:&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p /&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AddRange(IEnumerable&amp;lt;UploadFile&amp;gt; files)
        {
            &lt;span class="kwrd"&gt;using&lt;/span&gt; (PixEntities ent = &lt;span class="kwrd"&gt;new&lt;/span&gt; PixEntities())
            {
                &lt;span class="kwrd"&gt;using&lt;/span&gt; (&lt;span class="kwrd"&gt;new&lt;/span&gt; ReadLock(entityLock))
                {

                    &lt;span class="kwrd"&gt;using&lt;/span&gt; (&lt;span class="kwrd"&gt;new&lt;/span&gt; WriteLock(entityLock))
                    {
                        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var file &lt;span class="kwrd"&gt;in&lt;/span&gt; files)
                        {
                            ent.AddToUploadFiles(file);
                            ent.SaveChanges();
                        }
                    }
                }
            }
        }&lt;/pre&gt;

&lt;pre class="csharpcode"&gt; &lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;

&lt;p&gt;As you seen, this has two main elements…I use a ReadLock (where I would normally read *from* the DB, in this case umm, I don’t :)) then I use a WriteLock to wrap any operation where I write to the DB. The observant will also notice what looks like a bug…I do ent.SaveChages() for each iteration of the loop…this is another SQLite quirk, it doesn’t support batch updates…and gives a weird error about file locks if you try :)&lt;/p&gt;

&lt;p&gt;The little locking class I use is from &lt;a href="http://dotnetcommandos.com/blogs/brianr/archive/2008/09/26/thread-safe-dictionary-in-net.aspx"&gt;here&lt;/a&gt;, but I’ve put it below for your use…anyway, this is part one of several parts of my experiences in working on &lt;a href="http://blog.cozwecan.com"&gt;cozwecan&lt;/a&gt;…stay tuned!&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;pre class="csharpcode"&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Locks
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; GetReadLock(ReaderWriterLockSlim locks)
        {
            &lt;span class="kwrd"&gt;bool&lt;/span&gt; lockAcquired = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            &lt;span class="kwrd"&gt;while&lt;/span&gt; (!lockAcquired)
                lockAcquired = locks.TryEnterUpgradeableReadLock(1);
        }


        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; GetReadOnlyLock(ReaderWriterLockSlim locks)
        {
            &lt;span class="kwrd"&gt;bool&lt;/span&gt; lockAcquired = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            &lt;span class="kwrd"&gt;while&lt;/span&gt; (!lockAcquired)
                lockAcquired = locks.TryEnterReadLock(1);
        }


        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; GetWriteLock(ReaderWriterLockSlim locks)
        {
            &lt;span class="kwrd"&gt;bool&lt;/span&gt; lockAcquired = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            &lt;span class="kwrd"&gt;while&lt;/span&gt; (!lockAcquired)
                lockAcquired = locks.TryEnterWriteLock(1);
        }


        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ReleaseReadOnlyLock(ReaderWriterLockSlim locks)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (locks.IsReadLockHeld)
                locks.ExitReadLock();
        }


        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ReleaseReadLock(ReaderWriterLockSlim locks)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (locks.IsUpgradeableReadLockHeld)
                locks.ExitUpgradeableReadLock();
        }


        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ReleaseWriteLock(ReaderWriterLockSlim locks)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (locks.IsWriteLockHeld)
                locks.ExitWriteLock();
        }


        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ReleaseLock(ReaderWriterLockSlim locks)
        {
            ReleaseWriteLock(locks);
            ReleaseReadLock(locks);
            ReleaseReadOnlyLock(locks);
        }


        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; ReaderWriterLockSlim GetLockInstance()
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; GetLockInstance(LockRecursionPolicy.SupportsRecursion);
        }


        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; ReaderWriterLockSlim GetLockInstance(LockRecursionPolicy recursionPolicy)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ReaderWriterLockSlim(recursionPolicy);
        }
    }


    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; BaseLock : IDisposable
    {
        &lt;span class="kwrd"&gt;protected&lt;/span&gt; ReaderWriterLockSlim _Locks;


        &lt;span class="kwrd"&gt;public&lt;/span&gt; BaseLock(ReaderWriterLockSlim locks)
        {
            _Locks = locks;
        }


        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Dispose();
    }


    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ReadLock : BaseLock
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; ReadLock(ReaderWriterLockSlim locks)
            : &lt;span class="kwrd"&gt;base&lt;/span&gt;(locks)
        {
            Locks.GetReadLock(&lt;span class="kwrd"&gt;this&lt;/span&gt;._Locks);
        }


        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Dispose()
        {
            Locks.ReleaseReadLock(&lt;span class="kwrd"&gt;this&lt;/span&gt;._Locks);
        }
    }


    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ReadOnlyLock : BaseLock
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; ReadOnlyLock(ReaderWriterLockSlim locks)
            : &lt;span class="kwrd"&gt;base&lt;/span&gt;(locks)
        {
            Locks.GetReadOnlyLock(&lt;span class="kwrd"&gt;this&lt;/span&gt;._Locks);
        }


        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Dispose()
        {
            Locks.ReleaseReadOnlyLock(&lt;span class="kwrd"&gt;this&lt;/span&gt;._Locks);
        }
    }


    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; WriteLock : BaseLock
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; WriteLock(ReaderWriterLockSlim locks)
            : &lt;span class="kwrd"&gt;base&lt;/span&gt;(locks)
        {
            Locks.GetWriteLock(&lt;span class="kwrd"&gt;this&lt;/span&gt;._Locks);
        }


        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Dispose()
        {
            Locks.ReleaseWriteLock(&lt;span class="kwrd"&gt;this&lt;/span&gt;._Locks);
        }
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;&lt;img src="http://mostlylucid.net/aggbug/1332.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Scott Galloway</dc:creator>
            <guid>http://mostlylucid.net/archive/2010/01/20/1332.aspx</guid>
            <pubDate>Wed, 20 Jan 2010 20:53:59 GMT</pubDate>
            <comments>http://mostlylucid.net/archive/2010/01/20/1332.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://mostlylucid.net/comments/commentRss/1332.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Threading update...what I actually do...</title>
            <link>http://mostlylucid.net/archive/2004/05/24/threading-update.what-i-actually-do.aspx</link>
            <description>&lt;p&gt;Should mention I suppose the I lied in yesterdays post on threading using .NET...mea cupla :-). In that post I mentioned using delegates for multi-threading and said that you always had to use EndInvoke to avoid a memory leak...well not quite, what i actually do is use the excellent &lt;a href="http://www.bearcanyon.com/dotnet/#FireAndForget"&gt;AsyncHelper class by Mike Woodring&lt;/a&gt;, this supports this syntax: &lt;/p&gt;&lt;p&gt;CalcAndDisplaySumDelegate d = new CalcAndDisplaySumDelegate(someCalc.Add);&lt;br /&gt;    AsyncHelper.FireAndForget(d, 2, 3);&lt;/p&gt;&lt;p&gt;No EndInvoke required as it takes care of this using a DynamicInvoke internally. Well, saves a few lines of code!&lt;br /&gt;&lt;/p&gt;&lt;img src="http://mostlylucid.net/aggbug/845.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Blog Author</dc:creator>
            <guid>http://mostlylucid.net/archive/2004/05/24/threading-update.what-i-actually-do.aspx</guid>
            <pubDate>Tue, 25 May 2004 00:03:00 GMT</pubDate>
            <comments>http://mostlylucid.net/archive/2004/05/24/threading-update.what-i-actually-do.aspx#feedback</comments>
            <wfw:commentRss>http://mostlylucid.net/comments/commentRss/845.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Delegate.BeginInvoke() and memory leaks...</title>
            <link>http://mostlylucid.net/archive/2003/11/19/delegate.begininvoke-and-memory-leaks.aspx</link>
            <description>&lt;p&gt;I'm getting increasingly involved in the world of Asynchrony and have been doing a bit of digging about into some of the pitfalls of multi-threading. &lt;br /&gt;I came across an interesting one today involving the use of BeginInvoke without a corresponding EndInvoke when using delegates...many books (including the one I'm using most right now, the excellent &lt;a href="http://www.amazon.co.uk/exec/obidos/ASIN/0596003471/mostlylucid-21"&gt;Programming .NET Components by Juval Lowy&lt;/a&gt;) mention that a good way to fire events asynchronously (i.e., not blocking) is to simple call BeginInvoke on the delegate - cool seems easy enough! &lt;br /&gt;Well, reading around a bit, I discovered &lt;a href="http://www.bearcanyon.com/dotnet/#FireAndForget"&gt;this by Mike Woodring&lt;/a&gt; which contains this statement: &lt;em&gt;"Starting with the 1.1 release of the .NET Framework, the SDK docs now carry a caution that mandates calling EndInvoke on delegates you've called BeginInvoke on in order to avoid potential leaks. This means you cannot simply "fire-and-forget" a call to BeginInvoke without the risk of running the risk of causing problems. " &lt;br /&gt;&lt;/em&gt;Now, I can't find the bit in the docs which says that, but &lt;a href="http://www.ondotnet.com/pub/a/dotnet/2003/02/24/asyncdelegates.html?page=2"&gt;another article &lt;/a&gt; at &lt;a href="http://www.ondotnet.com/dotnet/"&gt;O'Reilly&lt;/a&gt; mentions the same thing... Well, based on this evidence, it would seem to be a good idea to avoid this potential leak, luckily &lt;a href="http://www.bearcanyon.com/dotnet/#FireAndForget"&gt;Mike's stuff&lt;/a&gt; has a handily little helper class which supports the &lt;a href="http://www.bearcanyon.com/dotnet/#FireAndForget"&gt;'Fire and Forget idiom'&lt;/a&gt; - dead easy, now I can have lovely fire and forget calls without worrying about unintended leaks :-)&lt;/p&gt;
&lt;p&gt;&lt;font color="#ff0000"&gt;UPDATE:&lt;/font&gt; Found the doc reference, if you have MSDN it's &lt;a href="ms-help://MS.NETFrameworkSDKv1.1/cpguidenf/html/cpovrasynchronousprogrammingoverview.htm"&gt;here&lt;/a&gt;, if not the on-line version is &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpovrasynchronousprogrammingoverview.asp"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;img src="http://mostlylucid.net/aggbug/653.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Blog Author</dc:creator>
            <guid>http://mostlylucid.net/archive/2003/11/19/delegate.begininvoke-and-memory-leaks.aspx</guid>
            <pubDate>Thu, 20 Nov 2003 02:54:00 GMT</pubDate>
            <comments>http://mostlylucid.net/archive/2003/11/19/delegate.begininvoke-and-memory-leaks.aspx#feedback</comments>
            <wfw:commentRss>http://mostlylucid.net/comments/commentRss/653.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Memory Leak - solved - or 'When STAThread Goes Bad'</title>
            <link>http://mostlylucid.net/archive/2003/11/17/memory-leak---solved---or-when-stathread-goes-bad.aspx</link>
            <description>I posted a little while ago about an odd 'Memory Leak' I was having...well, after several days of trawling (and annoying &lt;a href="http://weblogs.asp.net/dwanta/"&gt;Data Wanta &lt;/a&gt;who's excellent email &lt;a href="http://www.aspnetemail.com/"&gt;component&lt;/a&gt; I was mistakenly blaming - sorry!), I finally found the answer! Turns out that the little [STAThread] attribute above the main class of the Comand Line app isn't so inoccuous after all - Dave pointed out &lt;a href="http://groups.google.com/groups?hl=en&amp;amp;lr=&amp;amp;ie=UTF-8&amp;amp;oe=UTF-8&amp;amp;frame=right&amp;amp;th=d80d655cf0d70930&amp;amp;seekm=ef9gTVwLDHA.1720%40TK2MSFTNGP11.phx.gbl#link1"&gt;this thread&lt;/a&gt; - apparently there's some sort of &lt;a href="http://groups.google.com/groups?hl=en&amp;amp;lr=&amp;amp;ie=UTF-8&amp;amp;oe=UTF-8&amp;amp;selm=eXa3ObcPDHA.3192%40tk2msftngp13.phx.gbl"&gt;bug in .NET&lt;/a&gt;  which can lead to what is effectively a leak when using multi-threading in a STAThreaded application!&lt;img src="http://mostlylucid.net/aggbug/647.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Blog Author</dc:creator>
            <guid>http://mostlylucid.net/archive/2003/11/17/memory-leak---solved---or-when-stathread-goes-bad.aspx</guid>
            <pubDate>Tue, 18 Nov 2003 07:40:00 GMT</pubDate>
            <comments>http://mostlylucid.net/archive/2003/11/17/memory-leak---solved---or-when-stathread-goes-bad.aspx#feedback</comments>
            <wfw:commentRss>http://mostlylucid.net/comments/commentRss/647.aspx</wfw:commentRss>
        </item>
    </channel>
</rss>