Blog Home  Home Feed your aggregator (RSS 2.0)  
A Random Walk Around .Net - A Better ReaderWriterLock Wrapper
 
 Friday, May 02, 2008

Due to the fact my background is in financial markets (trading systems to be exact), I find my self continuously trying to scrounge up milliseconds by code improvements.  My weapon of choice is parallel processing or otherwise called threading.  Over the years it has been both my greatest asset any my most malevolent foe.  Many have commented on the impeding doom of mutable states and many core processors in software design; hence functional programming.

            I have aspiration to neither speak about functional programming nor give a class on threading best practices.  Instead, I am interested in providing an easier ReaderWriterLock schematic; most likely to the joy of my team.

            The “lock{}” keyword (or “SyncLock” keyword for VB.NET) is very useful and concise in its usage; though anyone trying to squeeze milliseconds knows the performance benefits of a ReaderWriterLock in many cases.  (Stop here if the previous statement doesn’t make sense to you and go Google the ReaderWriterLock.)  However, the implementation of a ReaderWriterLock requires much more code and can cause dead locks if implemented incorrectly.

            Thus, I came up with the attached solution.  It offers improvements on two fronts.  One, it allows a user to retry a function N number of times before raising an exception.  Second, it ensures the locks are acquired and released correctly.

            I am not exactly thrilled with this design because the use of anonymous methods makes for a non simple solution.  Nevertheless, I think it is better then writing the internalized code in ever method that needs to be locked.  Finally, I have not performance tested this yet; but I will post later with results.

public class ClassThanNeedsLocking
    {
        ReTryReaderWriterLock _rw = new ReTryReaderWriterLock();
        private Dictionary<double, double> _valueMap;

        public ClassThanNeedsLocking()
        {
            this._valueMap = new Dictionary<double, double>();
        }

        public void AddSomething(double key, double value)
        {
            ReTryReaderWriterLock.FunctionalityToLock temp = delegate
            {
                this._valueMap.Add(key, value);
            };
            this._rw.WriterLockFunction(temp, 100, 5, 10);
        }

        public double GetSomething(double key)
        {
            double value = 0;
            ReTryReaderWriterLock.FunctionalityToLock temp = delegate
            {
                if (this._valueMap.TryGetValue(key, out value))
                {
                    throw new ArgumentException("Key Does Not Exist.", "key");
                }
            };
            this._rw.ReaderLockFunction(temp, 100, 5, 10);
            return value;
        }

    }

    public class ReTryReaderWriterLock
    {
        public delegate void FunctionalityToLock();

        private delegate void RepeatTryLock(int timesTried);
        private ReaderWriterLock _rw = new ReaderWriterLock();
        private ILock _reader = new ReaderLock();
        private ILock _writer = new WriterLock();

        public void ReaderLockFunction(FunctionalityToLock function, int timeOutPerTry, int timesToTry, int timeToWaitBeforeTryingAgain)
        {
            LockFunction(function, timeOutPerTry, timesToTry, timeToWaitBeforeTryingAgain, this._reader);
        }

        public void WriterLockFunction(FunctionalityToLock function, int timeOutPerTry, int timesToTry, int timeToWaitBeforeTryingAgain)
        {
            LockFunction(function, timeOutPerTry, timesToTry, timeToWaitBeforeTryingAgain, this._writer);
        }

        private void LockFunction(FunctionalityToLock function, int timeOutPerTry, int timesToTry, int timeToWaitBeforeTryingAgain, ILock typeOfLock)
        {
            RepeatTryLock repeater = null;
            repeater = delegate(int timesTried)
            {
                try
                {
                    typeOfLock.Acquire(this._rw, timeOutPerTry);
                    function();
                }
                catch (ApplicationException)
                {
                    if (timesTried < timesToTry)
                    {
                        Thread.Sleep(timeToWaitBeforeTryingAgain);
                        timesTried += 1;
                        repeater(timesTried);
                        return;
                    }
                    throw;
                }
                finally
                {
                    typeOfLock.Release(this._rw);
                }
            };

            repeater(0);
        }

        private interface ILock
        {
            void Acquire(ReaderWriterLock rw, int timeOutPerTry);
            void Release(ReaderWriterLock rw);
        }

        private class ReaderLock : ILock
        {
            public void Acquire(ReaderWriterLock rw, int timeOutPerTry)
            {
                rw.AcquireReaderLock(timeOutPerTry);
            }

            public void Release(ReaderWriterLock rw)
            {
                if (rw.IsReaderLockHeld == true)
                {
                    rw.ReleaseReaderLock();
                }
            }
        }

        private class WriterLock : ILock
        {
            public void Acquire(ReaderWriterLock rw, int timeOutPerTry)
            {
                rw.AcquireWriterLock(timeOutPerTry);
            }

            public void Release(ReaderWriterLock rw)
            {
                if (rw.IsWriterLockHeld == true)
                {
                    rw.ReleaseWriterLock();
                }
            }
        }
    }
Friday, May 02, 2008 9:24:10 PM (Central Standard Time, UTC-06:00)  #    Comments [0]    | 
Comments are closed.
Copyright © 2010 Yezdaan Baber. All rights reserved.
DasBlog 'Portal' theme by Johnny Hughes.
Pick a theme: