in

ASP.NET Weblogs

Eddie Garmon's Weblog

some architecture, some c#

June 2008 - Posts

  • Sync Enumerator update.

    After a few more unit tests, I have fixed an issue with the GetSyncEnumerator method.

    The origional had 2 issues.

    1. was that the lock was being released too soon.
    2. was that a write in the middle of a long enumeration would cause a race and/or a deadlock.

    The fix was to 'write' lock for enumeration, and not to 'use' the lock, but to let the design of IDisposable on the enumerator itself work as intended.

    /// <summary>
    /// Gets a synchronized enumerator.
    /// </summary>
    /// <typeparam name="TValue">The type of the value.</typeparam>
    /// <param name="getEnumeratorFunction">The get enumerator function.</param>
    /// <returns></returns>
    public IEnumerator<TValue> GetSynchronizedEnumerator<TValue>(Func<T, IEnumerator<TValue>> getEnumeratorFunction) {
        Guard.ArgumentNotNull(getEnumeratorFunction, "getEnumeratorFunction");

        //cheat here and write block for enumeration.
        //otherwize a write during a long enumeration can cause a race.
        SynchronizedWriter synchronizedWriter = null;
        SynchronizedEnumerator<TValue> synchronizedEnumerator = null;
        try {
            synchronizedWriter = new SynchronizedWriter(_readerWriter);
            IEnumerator<TValue> enumerator = getEnumeratorFunction(_instance);
            synchronizedEnumerator = new SynchronizedEnumerator<TValue>(synchronizedWriter, enumerator);
            return synchronizedEnumerator;
            //When the enumerator disposes, the lock is released.
        } catch {
            if (synchronizedEnumerator != null) {
                synchronizedEnumerator.Dispose();
            } else if (synchronizedWriter != null) {
                synchronizedWriter.Dispose();
            }
            throw;
        }
    }

    The linked code has been updated.

  • Synchronization, ReaderWriterLockSlim, and Lambdas

    Here is a synchronization wrapper that I wrote to wrap any object, and an implementation of a SynchronizedDictionary to show how to use it.

    I offer this code as-is without any waranty to fitness, to the public domain, for any purpose you see fit.

    Get a text version of this code here.

    On with the show:

    [UPDATE: get the code via the link, only ideas are shown below.] 

    Synchronized<T>:
    wraps an instance of type T.

    Contains 3 functions:

    1. public TValue Read<TValue>(Func<T, TValue> readFunction)
       - inside a reader lock, executes the readFunction.
    2. public bool Write(Func<T, bool> writeFunction)
       - inside a writer lock, executes the writeFunction, which should return the success nature of the write.
    3. public IEnumerator<TValue> GetSynchronizedEnumerator<TValue>(Func<T, IEnumerator<TValue>> getEnumeratorFunction)
      - returns an enumerator wrapped in a lock that releases when it is disposed.

    An example of how to use the Synchronized<T> class:

    namespace SynapticPop.DataStructures.Dictionaries {
      public class SynchronizedDictionary<TKey, TValue> : IDictionary<TKey, TValue> {
        private readonly Synchronized<IDictionary<TKey, TValue>> _synchronized;

        public SynchronizedDictionary(IDictionary<TKey, TValue> dictionary) {
          _synchronized = new Synchronized<IDictionary<TKey, TValue>>(dictionary);
        }

        ...

        public int Count {
          get { return _synchronized.Read(dictionary => dictionary.Count); }
        }

        ...

        public void Add(TKey key, TValue value) {
          _synchronized.Write(dictionary => { dictionary.Add(key, value); return true; });
        }

        ...

        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
          return _synchronized.GetSynchronizedEnumerator(dictionary => dictionary.GetEnumerator());
        }

        ...
    }

     

More Posts