in

ASP.NET Weblogs

Eddie Garmon's Weblog

some architecture, some c#

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

    ...
}

 

Comments

 

Richard said:

Your GetSynchronizedEnumerator function always disposes of the SynchronizedReader instance before the method returns. You should change it to:

SynchronizedReader synchronizedReader = new SynchronizedReader(_readerWriter);

try

{

   IEnumerator<TValue> enumerator = getEnumeratorFunction(_instance);

   return new SynchronizedEnumerator<TValue>(synchronizedReader, enumerator);

}

catch (Exception)

{

   synchronizedReader.Dispose();

   throw;

}

June 28, 2008 8:55 AM
 

gOODiDEA.NET said:

Web CSS Layout Cheats .NET Synchronization, ReaderWriterLockSlim, and Lambdas CodeComment.NET Creating

June 29, 2008 8:26 PM
 

gOODiDEA said:

WebCSSLayoutCheats.NETSynchronization,ReaderWriterLockSlim,andLambdasCodeComment.NETC...

June 29, 2008 8:26 PM
 

UltimateRinger said:

Richard, the problem was with in the using in general.

I also found another condition when trying to write while doing a long enumeration. The code has been updated.

Also, your catch block will never get executed unless there is is an error actually getting the enumerator, therefore I added back in the Guard statements that were removed.

June 30, 2008 10:13 AM
 

Richard said:

The code in the catch block only needs to be executed if there is an error creating the SynchronizedEnumerator instance. In all other cases, the SynchronizedEnumerator takes over responsibility for calling Dispose on the synchronizedReader instance.

Adding a Guard statement to check for a null argument will prevent some errors, but not all. For example, the getEnumeratorFunction may throw an exception, or there may not be enough memory available to create the enumerator or SynchronizedEnumerator instances.

June 30, 2008 2:04 PM
 

UltimateRinger said:

Richard, I see your point. Generally if an exception occurs in either of the manner you speak, then letting the exception bubble is the proper course. Given my last change, I do need to release the lock, thanks.

July 1, 2008 9:03 AM

Leave a Comment

(required)  
(optional)
(required)  
Add