<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<channel>
	<title>Comments on: &quot;Using&quot; ReaderWriterLockSlim</title>
	<atom:link href="http://thevalerios.net/matt/2008/09/using-readerwriterlockslim/feed/" rel="self" type="application/rss+xml" />
	<link>http://thevalerios.net/matt/2008/09/using-readerwriterlockslim/</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Wed, 28 Apr 2010 12:28:38 -0500</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
		<item>
		<title>By: Nathan</title>
		<link>http://thevalerios.net/matt/2008/09/using-readerwriterlockslim/comment-page-1/#comment-4012</link>
		<dc:creator>Nathan</dc:creator>
		<pubDate>Mon, 24 Nov 2008 12:48:50 +0000</pubDate>
		<guid isPermaLink="false">http://thevalerios.net/matt/2008/09/using-readerwriterlockslim/#comment-4012</guid>
		<description>After a couple of questions got raised about this I have posted a detailed article addressing the deadlock condition discussed in the comments here: &lt;a href=&quot;http://www.nobletech.co.uk/Articles/&quot; rel=&quot;nofollow&quot;&gt;http://www.nobletech.co.uk/Articles/&lt;/a&gt;.
PS. My code posted above doesn&#039;t check what you&#039;re not already in a lock before acquiring a new one. Of course the lock itself will throw an exception if you haven&#039;t allowed recursion on it, but if you have then you will need to do this to make sure that each lock you acquire is released correctly at the right time. The full code for the lock manager including these checks is available on the page I mentioned.</description>
		<content:encoded><![CDATA[<p>After a couple of questions got raised about this I have posted a detailed article addressing the deadlock condition discussed in the comments here: <a href="http://www.nobletech.co.uk/Articles/" rel="nofollow">http://www.nobletech.co.uk/Articles/</a>.<br />
PS. My code posted above doesn&#8217;t check what you&#8217;re not already in a lock before acquiring a new one. Of course the lock itself will throw an exception if you haven&#8217;t allowed recursion on it, but if you have then you will need to do this to make sure that each lock you acquire is released correctly at the right time. The full code for the lock manager including these checks is available on the page I mentioned.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Nathan Phillips</title>
		<link>http://thevalerios.net/matt/2008/09/using-readerwriterlockslim/comment-page-1/#comment-3599</link>
		<dc:creator>Nathan Phillips</dc:creator>
		<pubDate>Fri, 14 Nov 2008 17:56:57 +0000</pubDate>
		<guid isPermaLink="false">http://thevalerios.net/matt/2008/09/using-readerwriterlockslim/#comment-3599</guid>
		<description>The updated code for the LockAcquirer class described by Steven is below. I&#039;ve renamed it to make it more obvious that it does not implicitly acquire the lock.

using System;
using System.Threading;

namespace NobleTech.Products.Library
{
    class ReaderWriterLockMgr : IDisposable
    {
        private ReaderWriterLockSlim _readerWriterLock = null;
        private bool _isDisposed = false;
        private enum LockTypes { None, Read, Write }
        LockTypes _enteredLockType = LockTypes.None;

        public ReaderWriterLockMgr(ReaderWriterLockSlim ReaderWriterLock)
        {
            _readerWriterLock = ReaderWriterLock;
        }

        public void EnterReadLock()
        {
            _readerWriterLock.EnterReadLock();
            _enteredLockType = LockTypes.Read;
        }

        public void EnterWriteLock()
        {
            _readerWriterLock.EnterWriteLock();
            _enteredLockType = LockTypes.Write;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_isDisposed)
            {
                if (disposing)
                {
                    switch (_enteredLockType)
                    {
                        case LockTypes.Read:
                            _readerWriterLock.ExitReadLock();
                            break;
                        case LockTypes.Write:
                            _readerWriterLock.ExitWriteLock();
                            break;
                    }
                }
            }

            _isDisposed = true;
        }
    }
}</description>
		<content:encoded><![CDATA[<p>The updated code for the LockAcquirer class described by Steven is below. I&#8217;ve renamed it to make it more obvious that it does not implicitly acquire the lock.</p>
<p>using System;<br />
using System.Threading;</p>
<p>namespace NobleTech.Products.Library<br />
{<br />
    class ReaderWriterLockMgr : IDisposable<br />
    {<br />
        private ReaderWriterLockSlim _readerWriterLock = null;<br />
        private bool _isDisposed = false;<br />
        private enum LockTypes { None, Read, Write }<br />
        LockTypes _enteredLockType = LockTypes.None;</p>
<p>        public ReaderWriterLockMgr(ReaderWriterLockSlim ReaderWriterLock)<br />
        {<br />
            _readerWriterLock = ReaderWriterLock;<br />
        }</p>
<p>        public void EnterReadLock()<br />
        {<br />
            _readerWriterLock.EnterReadLock();<br />
            _enteredLockType = LockTypes.Read;<br />
        }</p>
<p>        public void EnterWriteLock()<br />
        {<br />
            _readerWriterLock.EnterWriteLock();<br />
            _enteredLockType = LockTypes.Write;<br />
        }</p>
<p>        public void Dispose()<br />
        {<br />
            Dispose(true);<br />
            GC.SuppressFinalize(this);<br />
        }</p>
<p>        protected virtual void Dispose(bool disposing)<br />
        {<br />
            if (!_isDisposed)<br />
            {<br />
                if (disposing)<br />
                {<br />
                    switch (_enteredLockType)<br />
                    {<br />
                        case LockTypes.Read:<br />
                            _readerWriterLock.ExitReadLock();<br />
                            break;<br />
                        case LockTypes.Write:<br />
                            _readerWriterLock.ExitWriteLock();<br />
                            break;<br />
                    }<br />
                }<br />
            }</p>
<p>            _isDisposed = true;<br />
        }<br />
    }<br />
}</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: matt</title>
		<link>http://thevalerios.net/matt/2008/09/using-readerwriterlockslim/comment-page-1/#comment-1988</link>
		<dc:creator>matt</dc:creator>
		<pubDate>Tue, 23 Sep 2008 20:05:00 +0000</pubDate>
		<guid isPermaLink="false">http://thevalerios.net/matt/2008/09/using-readerwriterlockslim/#comment-1988</guid>
		<description>Wow, thanks Steven.  That is incredibly sneaky.  I&#039;ll definitely take another look at that.</description>
		<content:encoded><![CDATA[<p>Wow, thanks Steven.  That is incredibly sneaky.  I&#8217;ll definitely take another look at that.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Steven</title>
		<link>http://thevalerios.net/matt/2008/09/using-readerwriterlockslim/comment-page-1/#comment-1986</link>
		<dc:creator>Steven</dc:creator>
		<pubDate>Tue, 23 Sep 2008 19:45:14 +0000</pubDate>
		<guid isPermaLink="false">http://thevalerios.net/matt/2008/09/using-readerwriterlockslim/#comment-1986</guid>
		<description>Hi Matt,

I want to warn you for the given solution. There is a subtle bug that can occur during asynchronous exceptions (read: thread abort exceptions). The problem is that there is a time frame between &quot;m_Lock.EnterReadLock();&quot; statement in the constructor and the start of the try statement. When a async exception happens in this time frame, the finally will never run and the &quot;m_Lock.ExitReadLock();&quot; will therefore not run either. This could then lead to a deadlock.

Note that the C# lock() statement (or in fact the Monitor.Enter call) doesn&#039;t have this problem, because the JIT has a specific optimization for this that eliminates the time frame. Your simple &#039;using&#039; statement doesn&#039;t have this &#039;feature&#039; and therefore, you&#039;ll need another way to protect yourself against this. You should consider to write code like this:

using (var locker = LockAcquirer(theLock))
{
	// Because the lock is acquired within the
	// try..finally, the operation is safe from
	// async exceptions.
	locker.AcquireReadLock();

	// access the shared state for reading here
}

From an usability perspective, this proposal is actually less pleasing, because users may forget to call AcquireReadLock() leaving your code open for race conditions. And if you really need to be this paranoid, of course depends on your system requirements and the frequency that async exceptions occur. Some hosts are pretty aggressive about killing threads (like ASP.NET and SQL Server).

Joe Duffy wrote an amazing article about this almost two years ago. You can read it here:
http://www.bluebytesoftware.com/blog/CommentView,guid,d9ff204a-a8a5-400e-bcbc-dedb90a7d11a.aspx
And as you could imagine, in response to Joe’s blog, I wrote about it too: http://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=21</description>
		<content:encoded><![CDATA[<p>Hi Matt,</p>
<p>I want to warn you for the given solution. There is a subtle bug that can occur during asynchronous exceptions (read: thread abort exceptions). The problem is that there is a time frame between &#8220;m_Lock.EnterReadLock();&#8221; statement in the constructor and the start of the try statement. When a async exception happens in this time frame, the finally will never run and the &#8220;m_Lock.ExitReadLock();&#8221; will therefore not run either. This could then lead to a deadlock.</p>
<p>Note that the C# lock() statement (or in fact the Monitor.Enter call) doesn&#8217;t have this problem, because the JIT has a specific optimization for this that eliminates the time frame. Your simple &#8216;using&#8217; statement doesn&#8217;t have this &#8216;feature&#8217; and therefore, you&#8217;ll need another way to protect yourself against this. You should consider to write code like this:</p>
<p>using (var locker = LockAcquirer(theLock))<br />
{<br />
	// Because the lock is acquired within the<br />
	// try..finally, the operation is safe from<br />
	// async exceptions.<br />
	locker.AcquireReadLock();</p>
<p>	// access the shared state for reading here<br />
}</p>
<p>From an usability perspective, this proposal is actually less pleasing, because users may forget to call AcquireReadLock() leaving your code open for race conditions. And if you really need to be this paranoid, of course depends on your system requirements and the frequency that async exceptions occur. Some hosts are pretty aggressive about killing threads (like ASP.NET and SQL Server).</p>
<p>Joe Duffy wrote an amazing article about this almost two years ago. You can read it here:<br />
<a href="http://www.bluebytesoftware.com/blog/CommentView,guid,d9ff204a-a8a5-400e-bcbc-dedb90a7d11a.aspx" rel="nofollow">http://www.bluebytesoftware.com/blog/CommentView,guid,d9ff204a-a8a5-400e-bcbc-dedb90a7d11a.aspx</a><br />
And as you could imagine, in response to Joe’s blog, I wrote about it too: <a href="http://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=21" rel="nofollow">http://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=21</a></p>
]]></content:encoded>
	</item>
</channel>
</rss>
