Using ReaderWriterLock part 2

Well the trouble with simple samples like the one I provided in part 1 is that well... they're too simple.  Some of the improvements that you can make in them won't work generally.  But nonetheless I think there's some interesting discussion possibilities.

Let's have a look at it again:

     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;
        }
    }

Simple enough but is this really doing what we want?  Several people suggested that we could cache the result that was computed on update.  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.  If we had other reader methods with different results we couldn't use that technique.  But there is something similar we could do that does work more generally.

     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;
            }
        }
    }

I think I like that better than the original but what about my 5 points?  Can I always do this?

Well I don't think so... let me give you a different example

     public class MixedUsers
    {
        private static System.Threading.ReaderWriterLock rw = 
            new System.Threading.ReaderWriterLock();

        private static InMemoryDatabase m = InitializeTheDatabase();
         // 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();
        }
    }

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?

Here are the original questions, I think they're still worth discussing but I'll give some information with regard to the original posting.

#1 Is this a good use of ReaderWriterLock?  What assumptions do you have to make about the frequency of the operations.

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.  So it's not an especially good candidate for a ReaderWriterLock.

#2 If UpdateUsefully were the method that was called nearly always would you give the same answer?

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.  There's not much reason for it.  But here's a question:  does it matter how often it is entered or does it matter more how many threads are doing it?

What about the last three questions, have we addressed these at all?

#3 What if ComputeSomethingUseful were called almost exclusively instead, does that change your answer?

#4 Is there a different approach to solve this particular problem that might be more robust generally?

#5 What "tiny" change could I make in this problem that would make ReaderWriterLock virtually essential?