I've not blogged for a while now...mainly due to being snowed under writing the developmentor's "Code Smarter with Design Patterns" course with my co-author Kevin Jones (Course Details ) and working at a local firm ( yes Chippenham has industry). My head is now full of a handful of posts I want to make, and I've finally found time to write this one...
Whilst writing the design pattern course I managed to stumble upon various variations of standard patterns, in the course we discuss various forms of the standard Singleton pattern. Such as ThreadScoped singleton where each thread has access to a single instance, rather than a single instance app domain wide, this is potentially useful for preventing contention where multiple threads are competing over the use of the singleton. But oddly enough I stumbled upon another use of the singleton pattern when developing an example of a CopyOnWrite proxy. There are times when multiple threads request a collection of items from some object. If all the threads are only reading from the collection life is good...If there is a potential for the threads to update the collection for their private use then we should really be returning a copy of the collection to each thread, this could be considered inefficient if the collection is only occasionally privately updated, and that is where the CopyOnWrite Proxy comes in. By returning a proxy to the collection as opposed to the collection itself we allow ourselves to control the access to the collection in such a way as to provide access to the shared view of the collection whilst the thread is only reading but the moment it attempts to update the collection the proxy takes a copy of the collection it is providing the proxy for, and from that moment on the proxy is now wrapping up the copy. The client is blissfully unaware of this.
Ok, so inside my proxy implementation all the methods that are deemed write operations need to determine if a copy has been made previously and if not make a copy. In other words I will have a piece of code that I only wish to run once for the life of the object, and only once. This sounded similar to the fact that in the case of a singleton type I only want one instance. In my case I wanted to define a method in a class that only ever gets run once.
For example I was creating a proxy for a List, thus inside my proxy type I implemented the method
public
void Insert(int index, T item)
{
// Write operation, so make a private copy of the list now
MakeCopy();
subject.Insert(index, item);
}
Where subject is the actual List. Clearly I don't want MakeCopy to run every time the insert method is called just the first time on this proxy. Simple you might say just test a Boolean flag to see if you have made a copy. Whilst this would be guaranteed to work in a non threaded environment it would not in a threaded environment, so now you end up writing code that performs some kind of synchronization prior to determining if you have made a copy or not.
In this scenario I could simply create a method called MakeCopyIfNeccessary() and call that from each write method, and make that method do the appropriate synchronization, to do this efficiently requires double check locking. However this got me thinking if there was a more re-usable way of doing this so that if I needed this functionality again I could somehow re-use not just the pattern but the code. Below is a type I defined which wraps up an Action delegate such that it will only invoke the delegate once, irrespective of the number of times you call DoOnlyOnce();
public
class
SingletonAction<T>
{
object onlyOnceLock = new
object();
private
Action<T> action;
public SingletonAction(Action<T> action)
{
this.action = action;
}
public
void DoOnlyOnce(T arg)
{
if (action != null)
{
SynchronizedDoOnlyOnce(arg);
}
}
private
void SynchronizedDoOnlyOnce(T arg)
{
lock (onlyOnceLock)
{
if (action != null)
{
action(arg);
action = null;
}
}
}
}
Inside my proxy class I create an instance of this type supplying it the corresponding method I wish to only be executed once.
class
CopyOnUpdateList<T> : IList<T>
{
private
IList<T> subject;
private
SingletonAction<object> makeCopy;
public CopyOnUpdateList(IList<T> list)
{
makeCopy = new
SingletonAction<object>(MakeCopy);
subject = list;
}
// ....
public
void Insert(int index, T item)
{
makeCopy.DoOnlyOnce(null);
subject.Insert(index, item);
}
}
However if it wrapped up as an anonymous method this would be more true to the values of the singleton pattern as that way the only way the code could be invoked was via my wrapper. Wrapping up an arbitrary method doesn't stop it from being invoked elsewhere.
public CopyOnUpdateList(IList<T> list)
{
makeCopy = new
SingletonAction<object>(delegate
{
// Code required to perform the subject copy
});
subject = list;
}
Now the "only" way that code can be run is via my wrapper class which ensures it only ever gets run once...
No comments:
Post a Comment