<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Rico Mariani's Performance Tidbits : locking</title><link>http://blogs.msdn.com/ricom/archive/tags/locking/default.aspx</link><description>Tags: locking</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Using ReaderWriterLock part 3 (last in this set)</title><link>http://blogs.msdn.com/ricom/archive/2006/05/15/598468.aspx</link><pubDate>Tue, 16 May 2006 03:32:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:598468</guid><dc:creator>ricom</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/ricom/comments/598468.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ricom/commentrss.aspx?PostID=598468</wfw:commentRss><description>&lt;P&gt;Well I think it's raining ReaderWriterLocks this month!&amp;nbsp; Jeff Richter has an &lt;A href="http://msdn.microsoft.com/msdnmag/issues/06/06/ConcurrentAffairs/default.aspx"&gt;article &lt;/A&gt;on MSDN that goes over a lot of the basics and some stuff that's a lot more than basic.&amp;nbsp; And then there's Vance Morrison's March &lt;A HREF="/vancem/archive/2006/03/28/563180.aspx"&gt;article&lt;/A&gt;&amp;nbsp;on the subject as well.&amp;nbsp; Lots of good stuff in both of those.&lt;/P&gt;
&lt;P&gt;And rounding things out, there's my little series of brain teasers -- &lt;A HREF="/ricom/archive/2006/05/05/590955.aspx"&gt;part 1&lt;/A&gt; and &lt;A HREF="/ricom/archive/2006/05/12/596407.aspx"&gt;part 2&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;I've got a good number of comments with regards to the simple problem I originally posed in part 1 and the more complicated one involving a database in part 2.&amp;nbsp; Thanks to all that posted or wrote!&lt;/P&gt;
&lt;P&gt;There's some recurring themes in the comments and they tend to speak to my five original questions so I'll try to summarize them here:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;ReaderWriterLock will have higher raw costs than Monitor 
&lt;LI&gt;The amount of work done inside the lock makes a huge difference in deciding which type of concurrency control you can afford 
&lt;LI&gt;The number of threads of each type (reader/writer) tends to matter more than the frequency of entry 
&lt;LI&gt;Sometimes the whole locking situation can be finessed by exposing read-only objects, however, 
&lt;LI&gt;The amount of data that is being shared limits the ability to finesse locking issues by creating read-only objects 
&lt;LI&gt;And last but not least ReaderWriterLock can be potentially upgraded&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;In part 2 I answered some of the original 5 questions (keeping in mind as usual I only give approximately correct answers because complete answers would require an entire book) but here they all are again with reference to the above.&lt;/P&gt;
&lt;P&gt;#1 Is this a good use of ReaderWriterLock?&amp;nbsp; What assumptions do you have to make about the frequency of the operations.&lt;/P&gt;
&lt;P&gt;The original code can be easily changed into an example where the write becomes atomic and the read only data is in some sort of immutable object.&amp;nbsp; So it's not an especially good candidate for a ReaderWriterLock.&lt;/P&gt;
&lt;P&gt;#2 If UpdateUsefully were the method that was called nearly always would you give the same answer?&lt;/P&gt;
&lt;P&gt;If that were the case then really we're blocked on the write side of the reader writer lock all the time and so we're just using it as an expensive Monitor.&amp;nbsp; There's not much reason for it.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;#3 What if ComputeSomethingUseful were called almost exclusively instead, does that change your answer?&lt;/P&gt;
&lt;P&gt;Here we're basically saying that read threads are very rare.&amp;nbsp; If that were the case we may as well just use a Monitor (i.e. standard lock) and forget the whole thing.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;#4 Is there a different approach to solve this particular problem that might be more robust generally?&lt;/P&gt;
&lt;P&gt;Several solutions involving immutable state were offered.&amp;nbsp; All of those are an excellent approach that often generalizes.&amp;nbsp; I offered an example where there is too much state to readily clone.&lt;/P&gt;
&lt;P&gt;#5 What "tiny" change could I make in this problem that would make ReaderWriterLock virtually essential?&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Create a situation where the lock must be upgraded sometimes (e.g. if the result is greater than 100 then reset).&lt;/P&gt;
&lt;P&gt;I'll leave you with one more variation on the original theme.&amp;nbsp; If we must create a lock with guaranteed upgrade to writer semantics (i.e. I say that I want to be upgradeable and I want to be the next writer for sure if I choose to upgrade) how would we build that?&lt;/P&gt;
&lt;P&gt;It might look something like this (although you could do it more effectively by building the functionality directly into ReaderWriterLock --for big units of work it won't matter much anyway).&lt;/P&gt;&lt;PRE&gt;    public class MixedUsers
    {
        private static Object myLock = new Object();

        private static System.Threading.ReaderWriterLock rw = 
            new System.Threading.ReaderWriterLock();

        private static int val1 = 0;
        private static int val2 = 0;

        // this method is called by many threads
        public static int ComputeSomethingUseful()
        {
            // disregarding timeout effects for now
            rw.AcquireReaderLock(-1);

            int result = val1 + val2;

            rw.ReleaseReaderLock();

            return result;
        }

        // this method is called by many threads
        public static int ComputeSomethingUsefulMaybeUpgrade(int v)
        {
            // note this does not block other readers
            lock (myLock)
            {
                // should we acquire the readerlock here?  
                // is it necessary?  
                // is it a good idea anyway?
                // is it a bad idea?

                int result = val1 + val2;

                if (result &amp;gt; v)
                {
                    // disregarding timeout effects for now
                    // this effectively waits for all readers to exit
                    // we are the only writer because we own myLock
                    // we could use UpgradeToWriterLock instead of myLock&lt;BR&gt;                    // if we didn't care that another writer got in before us,&lt;BR&gt;                    // but then we'd have to revalidate val1 and val2

                    rw.AcquireWriterLock(-1);

                    val1 = 0;
                    val2 = 0;
                    result = 0;

                    rw.ReleaseWriterLock();
                    return result;
                }

                // release the readerlock here if you think it must be acquired above  

                return result;
            }
        }

        // this method is called by many threads
        public static int UpdateUsefully(int v1, int v2)
        {
            lock (myLock)
            {
                rw.AcquireWriterLock(-1);  // looks redundant but is it?

                val1 += v1; // note coordination of updates
                val2 += v2; // these two sums need to happen atomically

                int result = val1 + val2;

                rw.ReleaseWriterLock();

                return result;
            }
        }
    }
&lt;/PRE&gt;
&lt;P&gt;There's some final code and I'll leave the analysis as an exercise to my readers. But I will say off hand that this kind of synchronization housekeeping is probably a bad idea given the very small amount of work we are synchronizing. So it's best to pretend that the body of the methods is meatier or really it's all moot.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=598468" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ricom/archive/tags/performance/default.aspx">performance</category><category domain="http://blogs.msdn.com/ricom/archive/tags/locking/default.aspx">locking</category></item><item><title>Using ReaderWriterLock part 2</title><link>http://blogs.msdn.com/ricom/archive/2006/05/12/596407.aspx</link><pubDate>Fri, 12 May 2006 22:31:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:596407</guid><dc:creator>ricom</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/ricom/comments/596407.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ricom/commentrss.aspx?PostID=596407</wfw:commentRss><description>&lt;P&gt;Well the trouble with simple samples like the one I provided in &lt;A href="/ricom/archive/2006/05/05/590955.aspx"&gt;part 1&lt;/A&gt; is that well... they're too simple.&amp;nbsp; Some of the improvements that you can make in them won't work generally.&amp;nbsp; But nonetheless I think there's some interesting discussion possibilities.&lt;/P&gt;
&lt;P&gt;Let's have a look at it again:&lt;/P&gt;&lt;PRE&gt;    public class MixedUsers
    {
        private static System.Threading.ReaderWriterLock rw = 
            new System.Threading.ReaderWriterLock();

        private static int val1 = 0;
        private static int val2 = 0;

        // this method is called by many threads
        public static int ComputeSomethingUseful()
        {
            // disregarding timeout effects for now
            rw.AcquireReaderLock(-1);

            int result = val1 + val2;

            rw.ReleaseReaderLock();

            return result;
        }

        // this method is called by many threads
        public static int UpdateUsefully(int v1, int v2)
        {
            rw.AcquireWriterLock(-1);

            val1 += v1; // note coordination of updates
            val2 += v2; // these two sums need to happen atomically

            int result = val1 + val2;

            rw.ReleaseWriterLock();

            return result;
        }
    }
&lt;/PRE&gt;
&lt;P&gt;Simple enough but is this really doing what we want?&amp;nbsp; Several people suggested that we could cache the result that was computed on update.&amp;nbsp; That's a good idea in fact as we could do that write atomically; I won't really explore that much though because it's really quite specific to this problem.&amp;nbsp; If we had other reader methods with different results we couldn't use that technique.&amp;nbsp; But there is something similar we could do that does work more generally.&lt;/P&gt;&lt;PRE&gt;    public class MixedUsers
    {
        private static Object myLock = new Object();

        class MyState
        {
            int val1;
            int val2;
            MyState(int v1, int v2) { val1 = v1; val2 = v2; }
        }

        private static MyState state;

        // this method is called by many threads
        public static int ComputeSomethingUseful()
        {
            MyState s = state;

            return s.val1 + s.val2;
        }

        // this method is called by many threads
        public static int UpdateUsefully(int v1, int v2)
        {
            lock (myLock)
            {
                MyState sNew = new MyState(state.val1 + v1, state.val2 + v2);
                state = sNew;  // object write is atomic
                return state.val1 + state.val2;
            }
        }
    }
&lt;/PRE&gt;
&lt;P&gt;I think I like that better than the original but what about my 5 points?&amp;nbsp; Can I always do this? &lt;/P&gt;
&lt;P&gt;Well I don't think so... let me give you a different example&lt;/P&gt;&lt;PRE&gt;    public class MixedUsers
    {
        private static System.Threading.ReaderWriterLock rw = 
            new System.Threading.ReaderWriterLock();

        private static InMemoryDatabase m = InitializeTheDatabase();&lt;/PRE&gt;&lt;PRE&gt;        // this method is called by many threads, regularly
        public static int ComputeSomethingUseful(int param)
        {
            // disregarding timeout effects for now
            rw.AcquireReaderLock(-1);

            int result = OneSecondComputationFromData(m, param);

            rw.ReleaseReaderLock();

            return result;
        }

        // this method is called by one threads once per minute or so
        public static void UpdateUsefully()
        {
            rw.AcquireWriterLock(-1);

            ReadExternalDataAndUpdateDatabaseInTenSeconds(m);

            rw.ReleaseWriterLock();
        }
    }
&lt;/PRE&gt;
&lt;P&gt;Now why is that last example such a clear winner? There are several factors. What if ReaderWriterLock is 20 times lower than a regular lock, is still the right choice? &lt;/P&gt;
&lt;P&gt;Here are the original questions, I think they're still worth discussing but I'll give some information with regard to the original posting.&lt;/P&gt;
&lt;P&gt;#1 Is this a good use of ReaderWriterLock?&amp;nbsp; What assumptions do you have to make about the frequency of the operations.&lt;/P&gt;
&lt;P&gt;The original code can be easily changed into an example where the write becomes atomic and the read only data is in some sort of immutable object.&amp;nbsp; So it's not an especially good candidate for a ReaderWriterLock.&lt;/P&gt;
&lt;P&gt;#2 If UpdateUsefully were the method that was called nearly always would you give the same answer?&lt;/P&gt;
&lt;P&gt;If that were the case then really we're blocked on the write side of the reader writer lock all the time and so we're just using it as an expensive Monitor.&amp;nbsp; There's not much reason for it.&amp;nbsp; But here's a question:&amp;nbsp; does it matter how often it is entered or does it matter more how many threads are doing it?&lt;/P&gt;
&lt;P&gt;What about the last three questions, have we addressed these at all?&lt;/P&gt;
&lt;P&gt;#3 What if ComputeSomethingUseful were called almost exclusively instead, does that change your answer?&lt;/P&gt;
&lt;P&gt;#4 Is there a different approach to solve this particular problem that might be more robust generally?&lt;/P&gt;
&lt;P&gt;#5 What "tiny" change could I make in this problem that would make ReaderWriterLock virtually essential?&amp;nbsp; &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=596407" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ricom/archive/tags/performance/default.aspx">performance</category><category domain="http://blogs.msdn.com/ricom/archive/tags/locking/default.aspx">locking</category></item><item><title>Using ReaderWriterLock -- are you getting what you think you're getting?</title><link>http://blogs.msdn.com/ricom/archive/2006/05/05/590955.aspx</link><pubDate>Fri, 05 May 2006 21:51:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:590955</guid><dc:creator>ricom</dc:creator><slash:comments>14</slash:comments><comments>http://blogs.msdn.com/ricom/comments/590955.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ricom/commentrss.aspx?PostID=590955</wfw:commentRss><description>&lt;P&gt;Oh boy, more locking problems for the weekend!&lt;/P&gt;
&lt;P&gt;Here's a more complicated lock that often gets used when it shouldn't and is avoided when it should be used.&amp;nbsp;&amp;nbsp; Like the other articles in this series I'll provide a bit of code and ask for comments, it's more fun that way :)&lt;/P&gt;
&lt;P&gt;OK, here's the code:&lt;/P&gt;&lt;PRE&gt;    public class MixedUsers
    {
        private static System.Threading.ReaderWriterLock rw = &lt;BR&gt;            new System.Threading.ReaderWriterLock();

        private static int val1 = 0;
        private static int val2 = 0;

        // this method is called by many threads&lt;BR&gt;        public static int ComputeSomethingUseful()
        {&lt;BR&gt;            // disregarding timeout effects for now
            rw.AcquireReaderLock(-1);&lt;BR&gt; &lt;BR&gt;            int result = val1 + val2;&lt;BR&gt;
&lt;BR&gt;            rw.ReleaseReaderLock();

            return result;
        }

        // this method is called by many threads&lt;BR&gt;        public static int UpdateUsefully(int v1, int v2)
        {
            rw.AcquireWriterLock(-1);

            val1 += v1; // note coordination of updates
            val2 += v2; // these two sums need to happen atomically

            int result = val1 + val2;

            rw.ReleaseWriterLock();

            return result;
        }
    }
&lt;/PRE&gt;
&lt;P&gt;Now here are the things I want you to think about:&lt;/P&gt;
&lt;P&gt;#1 Is this a good use of ReaderWriterLock?&amp;nbsp; What assumptions do you have to make about the frequency of the operations.&lt;/P&gt;
&lt;P&gt;#2 If UpdateUsefully were the method that was called nearly always would you give the same answer?&lt;/P&gt;
&lt;P&gt;#3 What if ComputeSomethingUseful were called almost exclusively instead, does that change your answer?&lt;/P&gt;
&lt;P&gt;#4 Is there a different approach to solve this particular problem that might be more robust generally?&lt;/P&gt;
&lt;P&gt;#5 What "tiny" change could I make in this problem that would make ReaderWriterLock virtually essential?&amp;nbsp; &lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=590955" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ricom/archive/tags/performance/default.aspx">performance</category><category domain="http://blogs.msdn.com/ricom/archive/tags/locking/default.aspx">locking</category></item><item><title>Putting your synchronization at the correct level -- solution</title><link>http://blogs.msdn.com/ricom/archive/2006/05/03/589327.aspx</link><pubDate>Wed, 03 May 2006 20:42:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:589327</guid><dc:creator>ricom</dc:creator><slash:comments>13</slash:comments><comments>http://blogs.msdn.com/ricom/comments/589327.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ricom/commentrss.aspx?PostID=589327</wfw:commentRss><description>&lt;P&gt;Of course when I say "solution", I really mean "my solution" because there's not really just one way to do this.&amp;nbsp; But this is an approach I like and I'll go over why I like it.&lt;/P&gt;Recall the code from the &lt;A href="/ricom/archive/2006/05/01/587750.aspx"&gt;original problem&lt;/A&gt;: (there was some very interesting discussion so it's worth clicking to see what people thought)&amp;nbsp;&lt;PRE&gt;    public class Counter
    {
        private string name;
        private int reads;
        private int writes;

        public Counter(string _name)
        {
            name = _name;
            reads = writes = 0;
        }

        public void AddRead()
        {
            lock(this) // point #1 -- do we like the three lines marked point #1 ?
            {
                reads++;
            }
        }

        public void AddWrite()
        {
            lock(this) // point #1 -- do we like the three lines marked point #1 ?
            {
                writes++;
            }
        }

        public void WriteCounts(TextWriter tw)
        {
            lock(this) // point #1 -- do we like the three lines marked point #1 ?
            {
                // point #4 -- do we even like this method for this class?
                tw.WriteLine("{0} {1} {2}", name, reads, writes);
            }
        }
    }

    public class Updater
    {
        private static Counter c1 = new Counter("Category 1");
        private static Counter c2 = new Counter("Category 2");
        private static Object myLock = new Object();

        // this method is called by many threads
        public static void DoWork(bool br1, bool bw1, bool br2, bool bw2)
        {
            lock (myLock)  //  point #2, do we need this? does it even belong?
            {
                if (br1) c1.AddRead();
                if (br2) c2.AddRead();
                if (bw1) c1.AddWrite();
                if (bw2) c2.AddWrite();

                // point #3 could we change the lock so that it didn't include these two slowish statements?

                c1.WriteCounts(Console.Out);
                c2.WriteCounts(Console.Out);
            }
        }
    }
&lt;/PRE&gt;
&lt;P&gt;Point #1&lt;/P&gt;
&lt;P&gt;I think it's a very bad idea to introduce locking into a low level class like this counter.&amp;nbsp; It has no awareness of what is going on in the overall scheme of things.&amp;nbsp; Generally classes like this with synchronization end up having redundant features that add complexity and cost for no benefit.&amp;nbsp; This is exactly what is happening here.&amp;nbsp;&amp;nbsp; We have every expectation of having to use several of these counters in tandem and therefore synchronization within any one counter is worthless.&lt;/P&gt;
&lt;P&gt;Point #2&lt;/P&gt;
&lt;P&gt;The lock here is inescapable.&amp;nbsp; Indeed it is fundamentally the purpose of this class to coordinate three resources -- the two counters and the output stream.&amp;nbsp; Removing this lock would put the onus on some higher level code which might otherwise remain blissfully ignorant of the coordination.&amp;nbsp;&amp;nbsp; Now the opposite could be true: if the higher level code has to do a variety of its&amp;nbsp;own synchronization then perhaps even this level is "too low" but it seems likely that this is a good fit.&amp;nbsp; Note the static entry point and the presence of high level actions such as logging.&lt;/P&gt;
&lt;P&gt;Point #3&lt;/P&gt;
&lt;P&gt;As it is written the code is trying to coordinate three resources.&amp;nbsp; Without changing the format we would be unable to decode the output in any meaningful way.&amp;nbsp; Furthermore we need some form of synchronization on the output because the API itself is not threadsafe.&amp;nbsp; We could lament that the writing might be slow, but since we are fundamentally required to write and it must be coordinated, just&amp;nbsp;splitting the lock won't help us -- we'd simply move the blocking elsewhere.&amp;nbsp; However perhaps there something that can be done to mitigate the cost.&amp;nbsp; I offer one such suggestion in my solution below.&lt;/P&gt;
&lt;P&gt;Point #4&lt;/P&gt;
&lt;P&gt;I certainly do not like the Writing functionality at this level -- it seems rather orthogonal to the problem of keeping read and write counts.&amp;nbsp; Does this really fit?&amp;nbsp; See &lt;A href="/ricom/archive/2006/04/26/584802.aspx"&gt;this other article&lt;/A&gt; for more thinking on these lines.&lt;/P&gt;
&lt;P&gt;So what would I suggest instead?&amp;nbsp; Perhaps something like this (though there are other good options)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;    public class Counter
    {
        private string name;
        private int reads;
        private int writes;

        public Counter(string _name)
        {
            name = _name;
            reads = writes = 0;
        }

        public void AddRead()
        {
            reads++;
        }

        public void AddWrite()
        {
            writes++;
        }

        public void FormatCounts(StringBuilder sb)
        {
            sb.AppendFormat("{0} {1} {2}", name, reads, writes);
        }
    }

    public class Updater
    {
        private static Counter c1 = new Counter("Category 1");
        private static Counter c2 = new Counter("Category 2");
        private static Object myLock = new Object();
        private static Object myOutputLock = new Object();
        private static StringBuilder sb = new StringBuilder(4096);
        private static long sequenceNumber = 0;

        // this method is called by many threads
        public static void DoWork(bool br1, bool bw1, bool br2, bool bw2)
        {
            StringBuilder sbOut = null;

            lock (myLock)
            {
                if (br1) c1.AddRead();
                if (br2) c2.AddRead();
                if (bw1) c1.AddWrite();
                if (bw2) c2.AddWrite();

                sb.AppendFormat("{0} ", sequenceNumber++);

                c1.FormatCounts(sb);
                sb.Append(" ");
                c2.FormatCounts(sb);

                sb.Append("\r\n");

                if (sb.Length &amp;gt;= 4000)
                {
                    sbOut = sb;
                    sb = new StringBuilder(4096);
                }
            }

            // note other threads can keep doing the main job
            // this thread becomes the output worker temporarily
            // you could do real async i/o here if you wanted
            // output could be out of order but sequence number allows decoding
            if (sbOut != null)
            {
                lock(myOutputLock)
                {
                    Console.WriteLine(sbOut.ToString());
                }
            }
        }
    }
&lt;/PRE&gt;
&lt;P&gt;And can you think of three reasons why I like that better? :)&lt;/P&gt;
&lt;P&gt;(Also it needs a simple flush method to handle shutdown -- left as an exercise for the reader :))&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=589327" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ricom/archive/tags/performance/default.aspx">performance</category><category domain="http://blogs.msdn.com/ricom/archive/tags/locking/default.aspx">locking</category></item><item><title>Putting your synchronization at the correct level</title><link>http://blogs.msdn.com/ricom/archive/2006/05/01/587750.aspx</link><pubDate>Mon, 01 May 2006 21:43:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:587750</guid><dc:creator>ricom</dc:creator><slash:comments>33</slash:comments><comments>http://blogs.msdn.com/ricom/comments/587750.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ricom/commentrss.aspx?PostID=587750</wfw:commentRss><description>&lt;P&gt;Continuing in what's turned into my series on locking advice, I have a new example for you of a typical problem that happens in class design.&amp;nbsp; As usual I've simplified this almost to the point of being silly to illustrate the problem.&amp;nbsp; Hopefully the crux of what is going on still shows through.&lt;/P&gt;
&lt;P&gt;The theme for today is that often synchronization is inserted into the wrong level of programming code.&amp;nbsp; Low level classes, like the Counter in this example, have very little idea what is going on in the world around them and so they can't make especially good synchronization decisions.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Often synchronization at the low level ends up&amp;nbsp;doing nothing useful, but instead only creates complexity and wastes cycles.&amp;nbsp; My "favorite" example of this is the availablity of synchronized collection classes which, like the Counter example below, have difficulty meeting the synchronization needs of their clients because they have no understanding of the overall unit of work and are therefore unhelpful when composed with other resources.&lt;/P&gt;&lt;PRE&gt;    public class Counter
    {
        private string name;
        private int reads;
        private int writes;

        public Counter(string _name)
        {
            name = _name;
            reads = writes = 0;
        }

        public void AddRead()
        {
            lock(this) // point #1 -- do we like the three lines marked point #1 ?
            {
                reads++;
            }
        }

        public void AddWrite()
        {
            lock(this) // point #1 -- do we like the three lines marked point #1 ?
            {
                writes++;
            }
        }

        public void WriteCounts(TextWriter tw)
        {
            lock(this) // point #1 -- do we like the three lines marked point #1 ?
            {
                // point #4 -- do we even like this method for this class?
                tw.WriteLine("{0} {1} {2}", name, reads, writes);
            }
        }
    }

    public class Updater
    {
        private static Counter c1 = new Counter("Category 1");
        private static Counter c2 = new Counter("Category 2");
        private static Object myLock = new Object();

        // this method is called by many threads
        public static void DoWork(bool br1, bool bw1, bool br2, bool bw2)
        {
            lock (myLock)  //  point #2, do we need this? does it even belong?
            {
                if (br1) c1.AddRead();
                if (br2) c2.AddRead();
                if (bw1) c1.AddWrite();
                if (bw2) c2.AddWrite();

                // point #3 could we change the lock so that it didn't include these two slowish statements?

                c1.WriteCounts(Console.Out);
                c2.WriteCounts(Console.Out);
            }
        }
    }
&lt;/PRE&gt;
&lt;P&gt;What are your thoughts on the marked points (1-4)?&amp;nbsp; What would a better Counter class look like to meet the needs of DoWork?&lt;/P&gt;
&lt;P&gt;(my "solution" is now available &lt;A HREF="/ricom/archive/2006/05/03/589327.aspx"&gt;here&lt;/A&gt;)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=587750" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ricom/archive/tags/performance/default.aspx">performance</category><category domain="http://blogs.msdn.com/ricom/archive/tags/locking/default.aspx">locking</category></item><item><title>Simplify your locking strategy -- simpler is better</title><link>http://blogs.msdn.com/ricom/archive/2006/04/28/586406.aspx</link><pubDate>Sat, 29 Apr 2006 01:29:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:586406</guid><dc:creator>ricom</dc:creator><slash:comments>18</slash:comments><comments>http://blogs.msdn.com/ricom/comments/586406.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ricom/commentrss.aspx?PostID=586406</wfw:commentRss><description>&lt;P&gt;Well I didn't mean to but it seems I'm writing a series of articles on locking.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Based on my last posting I got several requests for a simple example of a case that could be improved with simpler locking.&amp;nbsp; Here's something of that ilk that's similar to something I encountered in The Real World.&amp;nbsp; The 2nd choice is based on what I recommended.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;    class FreeThreaded1
    {
        private static volatile Dictionary &lt;STRING, string&gt; dict = new Dictionary&lt;STRING, string&gt;();

        static void UpdateThreadProc() // one thread runs this
        {
            for (;;)
            {
                using (StreamReader sr = new StreamReader("c:\\pickupdir\\dictionary.txt"))
                {
                    lock (dict)
                    {
                        dict.Clear();

                        String line = null;

                        while (null != (line = sr.ReadLine()))
                        {
                            int iTab = line.IndexOf('\t');

                            if (iTab &amp;lt; 1 || iTab &amp;gt; line.Length-2)
                                continue;

                            string key = line.Substring(0, iTab);
                            string val = line.Substring(iTab+1);

                            dict.Add(key, val);
                        }
                    }
                }

                System.Threading.Thread.Sleep(5000);
            }
        }

        static string ReadEntry(string s)  // this is called by many threads at random
        {
            lock (dict)
            {
                return dict[s];
            }
        }
    }


    class FreeThreaded2
    {
        private static volatile Dictionary &lt;STRING, string&gt; dict = new Dictionary&lt;STRING, string&gt;();

        static void UpdateThreadProc() // one thread runs this
        {
            for (;;)
            {
                using (StreamReader sr = new StreamReader("c:\\pickupdir\\dictionary.txt"))
                {
                    Dictionary&lt;STRING, string&gt; d = new Dictionary&lt;STRING, string&gt;();
                    String line = null;

                    while (null != (line = sr.ReadLine()))
                    {
                        int iTab = line.IndexOf('\t');

                        if (iTab &amp;lt; 1 || iTab &amp;gt; line.Length-2)
                            continue;

                        string key = line.Substring(0, iTab);
                        string val = line.Substring(iTab+1);

                        d.Add(key, val);
                    }
                    dict = d;
                }

                System.Threading.Thread.Sleep(5000);
            }
        }

        static string ReadEntry(string s)  // this is called by many threads at random
        {
            return dict[s];
        }
    }
&lt;/PRE&gt;Can you spot at least 3 reasons why I would like the 2nd one better? Not that it's perfect...&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=586406" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ricom/archive/tags/performance/default.aspx">performance</category><category domain="http://blogs.msdn.com/ricom/archive/tags/locking/default.aspx">locking</category></item><item><title>Locking -- Isolation -- Unit of Work -- Performance -- Solution</title><link>http://blogs.msdn.com/ricom/archive/2006/04/26/584802.aspx</link><pubDate>Thu, 27 Apr 2006 08:33:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:584802</guid><dc:creator>ricom</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/ricom/comments/584802.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ricom/commentrss.aspx?PostID=584802</wfw:commentRss><description>&lt;P&gt;A&amp;nbsp;few days ago I posted&amp;nbsp;&lt;A href="/ricom/archive/2006/04/24/582643.aspx"&gt;a concurrency problem for commentary &lt;/A&gt;and I got a very nice set of responses.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Now I can't say that there is any answer to this problem that I would say is universally correct but there are some interesting observations that we can/should make about the proffered code.&amp;nbsp; Many of these points were covered in the commentary but not everything was so hopefully you’ll still find it interesting to read this.&amp;nbsp; Again, as always, forgive me for generalizing in the interest of greater clarity in some cases below.&lt;/P&gt;
&lt;P&gt;Now the first solution had one lock controlling all the access.&amp;nbsp; This has perhaps the most understandable behavior of the two solutions and maybe about as understandable as we can get.&amp;nbsp;&amp;nbsp; &lt;/P&gt;&lt;PRE&gt;    // it's easy to explain what this does
    class ExampleCoarse
    {
        public ExampleCoarse() {}
        private Object myLock = new Object();
        private int count;

        public void DoIt(StreamWriter sw)
        {
            lock(myLock)
            {
                long ticks = DateTime.Now.Ticks;
                int count = IncrementCount();
                LogToStream(sw, ticks, count);
            }
        }

        private int IncrementCount()
        {
            return ++count;
        }

        private void LogToSteam(StreamWriter sw, long ticks, int count)
        {
            sw.WriteLine("{0} {1}", ticks, count);
        }
    }
&lt;/PRE&gt;
&lt;P&gt;The first thing to notice is that I said in the assumptions that there was only going to be one instance of this object – and yet the object has no static members.&amp;nbsp; Presumably that was done to allow for several logically independent copies of the object at some point in the future.&amp;nbsp; If the “count” and “myLock” members were truly static then the single instance choice would be locked in forever.&amp;nbsp; As it stands the users of the object are sort of forced to deal with the fact that there is some shared instance because they must provide the “this” pointer.&amp;nbsp; Fair enough I suppose.&lt;/P&gt;
&lt;P&gt;But even in this simplest form of the code there are at least two other concerns.&amp;nbsp; It appears that writing to the stream will be serialized … but will it?&amp;nbsp; Well not exactly.&amp;nbsp; The StreamWriter (sw) provided is external to the class.&amp;nbsp; We have no idea if it is going to be shared by other threads.&amp;nbsp; If it is then it will have to be the case that this is the only place that StreamWriter is used because otherwise lock(myLock) will not offer any protection (see &lt;A href="/ricom/archive/2006/03/22/558584.aspx"&gt;“Same Resource, Same Lock or else locking won't give you the protection you need”&lt;/A&gt; for more details on this).&lt;/P&gt;
&lt;P&gt;That’s bad enough.&amp;nbsp; But can we say that it is wise to even use the external StreamWriter?&amp;nbsp; What does it do?&amp;nbsp; The trouble with StreamWriters is that they abstract the underlying stream with a nice interface.&amp;nbsp; Coincidentally that’s also what’s good about them.&amp;nbsp; So what is going to Actually Happen when we call sw.WriteLine()?&amp;nbsp; Well the answer is pretty much anything could happen.&amp;nbsp; For all we know the underlying Stream synchronously sends a letter to Grandma via US certified return-receipt air mail.&amp;nbsp; So is it a good idea to call such a method inside a lock?&amp;nbsp; Well… if we have a good understanding of what the stream is going to be for other reasons (not shown here) then maybe. But if this was framework code, it might be an astonishingly bad idea indeed.&lt;/P&gt;
&lt;P&gt;Looks like for even the simple code, as written, to get good results it needs to make some pretty significant assumptions.&lt;/P&gt;
&lt;P&gt;Let's have a look at the second version now:&lt;/P&gt;&lt;PRE&gt;    // it's not so easy to explain this... or how to use it.. but is it better?
    class ExampleFine
    {
        public ExampleFine() {}
        private Object myLock = new Object();
        private int count;

        public void DoIt(StreamWriter sw)
        {
            long ticks = DateTime.Now.Ticks;
            int count = IncrementCount();
            LogToStream(sw, ticks, count);
        }

        private int IncrementCount()
        {
            int c = System.Threading.Interlocked.Increment(count);
            return c;
        }

        private void LogToSteam(StreamWriter sw, long ticks, int count)
        {
            lock (myLock)
            {
                sw.WriteLine("{0} {1}", ticks, count);
            }
        }
    }
&lt;/PRE&gt;
&lt;P&gt;That's of course more complicated, but what does it do?&amp;nbsp; Well naturally it has all the same issues as the "easy" case. But additionally it suffers from the fact that it's basically impossible to characterize the output.&amp;nbsp; Counts and ticks do not necessarily increase together and they can also be out of order in the file.&amp;nbsp; The count could be arbitrarily unrelated to the ticks.&amp;nbsp; Is it at least faster?&amp;nbsp; Hrm... maybe... it does have finer locks but then the interlocked operation isn't cheap either and we don't know if the stream is fast (like say a memory stream) or slow (like that letter to Gramma).&amp;nbsp; If the streaming operation is comparatively quick then contention would be low and the extra locks would just slow us down.&amp;nbsp; On the other hand a very slow stream will dominate the cost as everyone is gonna be waiting for Gramma&amp;nbsp; for so long that the rest of the time isn’t going to matter a whit.&amp;nbsp; So somewhere in between there would be a cutoff where the extra concurrency is paying for the extra locking.&lt;BR&gt;&lt;BR&gt;Wow that’s complicated.&lt;BR&gt;&lt;BR&gt;So in return for getting streamed output that’s totally meaningless we get…maybe nothing at all.&amp;nbsp; And don’t forget the Gramma stream could be asynchronous – further confusing the situation for both cases.&lt;/P&gt;
&lt;P&gt;I’m not really liking that second choice very much at all at this point.&lt;/P&gt;
&lt;P&gt;Could we do better?&amp;nbsp; Yes I think we could.&amp;nbsp; Here’s a couple of suggestions:&lt;/P&gt;&lt;PRE&gt;    // it's easy to explain what this does
    class ExampleHybrid
    {
        public ExampleHybrid() {}
        private Object myLock = new Object();
        private int count;

        public void DoIt(StreamWriter sw)
        {
            lock(myLock)
            {
                long ticks = DateTime.Now.Ticks;
                int count = IncrementCount();
            }

            LogToStream(sw, ticks, count);
        }

        private int IncrementCount()
        {
            return ++count;
        }

        private void LogToSteam(StreamWriter sw, long ticks, int count)
        {
            sw.WriteLine("{0} {1}", ticks, count);
        }
    }
&lt;/PRE&gt;
&lt;P&gt;In this case we’re basically coming right out and saying to our callers that the StreamWriter (sw) they provide us better not be shared with other threads, or else it better be internally threadsafe. Either way we’re staying out of it. And by the way we aren’t guaranteeing the output order but we are guaranteeing that at least the tick will match the counts in some meaningful way. It’s an interesting compromise – and actually easier to understand than the previous case. If the stream is slow at least we won’t be holding a lock while it does its business. &lt;/P&gt;
&lt;P&gt;And maybe one last choice for discussion&lt;/P&gt;&lt;PRE&gt;    // it's easy to explain what this does
    class ExampleNoOutput
    {
        public ExampleNoOutput() {}
        private Object myLock = new Object();
        private int count;

        public void DoIt(out long ticksOut, out int countOut)
        {
            lock(myLock)
            {
                ticksOut = DateTime.Now.Ticks;
                countOut = IncrementCount();
            }
        }

        private int IncrementCount()
        {
            return ++count;
        }
    }
&lt;/PRE&gt;
&lt;P&gt;And in this last example we finesse the output issues by declining to take a dependence on the stream entirely.&amp;nbsp; “Leave me out of your output logging problems”, says this class, “I wash my hands of all that messy I/O”.&lt;/P&gt;
&lt;P&gt;This could perhaps be the wisest course of all.&amp;nbsp; Although the services are more modest they are readily understood and any desired logging strategy can be built on top of them.&amp;nbsp; Whatever chuncking, synchronization, etc. is up to higher level code that is likely be better capable of making that decision intelligently.&amp;nbsp; Moving synchronization primitives “up the stack” to code with more overall “awareness” of what is going on is a common theme to get more sensible synchronization.&amp;nbsp; Definitely something you should keep in mind.&lt;/P&gt;
&lt;P&gt;Is there an overall winner?&amp;nbsp; Hardly.&amp;nbsp; Though I think the second of the two original versions is probably the overall loser.&lt;/P&gt;
&lt;P&gt;Thanks very much for the thoughtful comments on the first posting.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=584802" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ricom/archive/tags/performance/default.aspx">performance</category><category domain="http://blogs.msdn.com/ricom/archive/tags/locking/default.aspx">locking</category></item><item><title>Locking -- Isolation -- Unit of Work -- Performance</title><link>http://blogs.msdn.com/ricom/archive/2006/04/24/582643.aspx</link><pubDate>Tue, 25 Apr 2006 05:54:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:582643</guid><dc:creator>ricom</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/ricom/comments/582643.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ricom/commentrss.aspx?PostID=582643</wfw:commentRss><description>&lt;P&gt;I've had&amp;nbsp;a bit of a locking/threading theme in some of my recent postings so I thought I'd continue that with a little problem.&amp;nbsp; Here's a (simplified) set of operations that is sort of an example of what you might need to do in a free threaded class.&amp;nbsp; Let's assume there is one instance of this class that is to be shared between multiple threads any of which might call the DoIt() function at any time.&lt;/P&gt;
&lt;P&gt;Here are two possible implementations that are like things I've seen in the past.&amp;nbsp; The question is:&amp;nbsp; Which of these is "better?"&amp;nbsp; Is there something that is (in some sense) better still?&amp;nbsp; What are the factors that influence this decision (Hint: see the title of this posting)&lt;/P&gt;
&lt;P&gt;You might have to scroll down to see the code depending on your browser because the &amp;lt;PRE&amp;gt; formatting seems to come out weird with the stylesheets in use here.&lt;/P&gt;&lt;PRE&gt;    // it's easy to explain what this does
    class ExampleCoarse
    {
        public ExampleCoarse() {}
        private Object myLock = new Object();
        private int count;

        public void DoIt(StreamWriter sw)
        {
            lock(myLock)
            {
                long ticks = DateTime.Now.Ticks;
                int count = IncrementCount();
                LogToStream(sw, ticks, count);
            }
        }

        private int IncrementCount()
        {
            return ++count;
        }

        private void LogToSteam(StreamWriter sw, long ticks, int count)
        {
            sw.WriteLine("{0} {1}", ticks, count);
        }
    }

    // it's not so easy to explain this... or how to use it.. but is it better?
    class ExampleFine
    {
        public ExampleFine() {}
        private Object myLock = new Object();
        private int count;

        public void DoIt(StreamWriter sw)
        {
            long ticks = DateTime.Now.Ticks;
            int count = IncrementCount();
            LogToStream(sw, ticks, count);
        }

        private int IncrementCount()
        {
            int c = System.Threading.Interlocked.Increment(count);
            return c;
        }

        private void LogToSteam(StreamWriter sw, long ticks, int count)
        {
            lock (myLock)
            {
                sw.WriteLine("{0} {1}", ticks, count);
            }
        }
    }
&lt;/PRE&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=582643" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ricom/archive/tags/performance/default.aspx">performance</category><category domain="http://blogs.msdn.com/ricom/archive/tags/locking/default.aspx">locking</category></item><item><title>Same Resource, Same Lock or else locking won't give you the protection you need</title><link>http://blogs.msdn.com/ricom/archive/2006/03/22/558584.aspx</link><pubDate>Thu, 23 Mar 2006 04:49:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:558584</guid><dc:creator>ricom</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/ricom/comments/558584.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ricom/commentrss.aspx?PostID=558584</wfw:commentRss><description>&lt;P&gt;I sometimes see funny locking patterns because there is&amp;nbsp;a mental assumption that the lock&amp;nbsp;keyword (via Monitor&amp;nbsp;features of the runtime)&amp;nbsp;automatically guards the contents of the locked region.&amp;nbsp; This isn't the case.&amp;nbsp; All that is guaranteed is that only one thread can hold the monitor (i.e. the locked object) at any moment.&amp;nbsp; This doesn't result in resource protection at all unless you, by policy, always take the same lock when accessing the same resource.&lt;/P&gt;
&lt;P&gt;So here are some (vastly simplified)&amp;nbsp;examples that work:&lt;/P&gt;&lt;PRE&gt;class T1
{
   private static Object myLock = new Object();

   private Object member1 etc. etc.
   private static Object member2 etc. etc.

   public void DoSomething(T1 him)
   {
       lock (myLock)
       {
        ... use this.member1, him.member1, or member2 // safe
       }
   }
}

class T2
{
   private Object myLock = new Object();
   private Object member1 etc. etc.

   public void DoSomething()
   {
       lock (myLock)
       {
        ... use this.member1 but no other member1 from any other object // safe
       }
   }
}
&lt;/PRE&gt;
&lt;P&gt;And here are&amp;nbsp; some (vastly simplified) examples that do NOT work:&lt;/P&gt;&lt;PRE&gt;class T3
{
   private Object myLock = new Object();

   private Object member1 etc. etc.
   private static Object member2 etc. etc.

   public void DoSomething()
   {
       lock (myLock)
       {
        ... use member2 // this is not safe
       }
   }
}

class T4
{
   private Object myLock = new Object();
   private Object member1 etc. etc.

   public void DoSomething(T4 him)
   {
       lock (myLock)
       {
        ... use him.member1  // not safe
       }
   }
}
&lt;/PRE&gt;&lt;PRE&gt;class T5 // the most nefarious of them all
{
   private Object myLock = new Object();
   private static Object myOtherLock = new Object();

   private Object member1 etc. etc.

   public void DoSomething(T1 him)
   {
       lock (myLock)
       {
        ... use this.member1 // not safe due to DoSomethingElse
       }
   }

   public void DoSomethingElse()
   {
       lock (myOtherLock)
       {
        ... use this.member1 // not safe due to DoSomething
       }
   }
}
&lt;/PRE&gt;
&lt;P&gt;Of course locking choices can have profound performance ramifications but that's not really the point here.&amp;nbsp; The thing to remember is that locking alone generally does not provide protection -- you get protection by applying a &lt;EM&gt;consistent &lt;/EM&gt;locking policy to a resource or set of resources.&lt;/P&gt;
&lt;P&gt;Sometimes, in the name of performance, complex locking schemes get invented but then race conditions are introduced so correctness goes out the window.&amp;nbsp; It's always important to remember that, as I'm fond of saying, "It's easy to make it fast if it doesn't have to work."&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=558584" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ricom/archive/tags/performance/default.aspx">performance</category><category domain="http://blogs.msdn.com/ricom/archive/tags/locking/default.aspx">locking</category></item></channel></rss>