Naboo

Thursday, December 14, 2006

Thread Safe Hashtable (C#)
There are not a lot articles around about Hashtable thread safety, oh maybe yes, but blame google.

Between thread-safe and thread-unsafe, there is something called "conditional thread-safe", which means each individual operation may be thread-safe, but certain sequences of operations may require external synchronization. The most common example of conditional thread safety is traversing an iterator returned from Hashtable or Vector(Java), or Collection(C#).
Example:

List stringList = new List();
stringList.Add("a");//pretty much synchronized
foreach(string s in stringList)
{
Console.WriteLine(s); //not safe. Add is allowed to happen within the foreach loop
}


Thus, if you do need loop the collection a lot while Add and Remove are also called frequently, you will get a lot "InvalidOperationException: Collection was modified, enumeration not allowed". The way to solve this will be to 2 steps:

  1. Wrap the collection with another class implement thread-safety for it.
  2. Whenever enumeration is needed, lock.
Example:
Step 1:
public class ThreadSafeDictionary : Dictionary
{
private object _syncRoot = new object();
public object SyncRoot()
{ return _syncRoot; }
public void SyncAdd(KeyFacetTuple key, ISet value)
{

lock(_syncRoot) { Add(key, value); }
}
public void SyncRemove(KeyFacetTuple key)
{
lock (_syncRoot) { Remove(key); }
}
public void SyncBatchRemove(ICollection removes)//To avoid too frequent locking/unlocking
{
lock (_syncRoot) {

foreach (string key in removes) { Remove(key); }
}
} }

Step 2:
put lock(threadSafeDictionary.SyncRoot) around any "foreach KeyValuePair" for this class

lock(threadSafeDictionary.SyncRoot)
{
foreach(KeyValuePair pair in threadSafeDictionary)
{
//do stuff
}
}

Of course, this implementation only ensures the foreach loop won't encounter embarrasing moments, remember the elements in the threadSafeDictionary could be non-primitive data types and they are not locked. E.g. it can be an dicationary, then you must be careful about what you want to do with ArrayList and ISet too.

Another way for thinking about this whole problem is, can we implement a data structure so that it keeps track of the Enumerators. If there is any Enumerators alive, no Add/Remove can be executed. Whether this thought is worthwhile depends on performance: using SyncRoot VS. tracking Enumerators, which one consumes less resource?

I am also planning to write up an interface for thread-safe data structure built on conditional-thread-safe data structure. Will update this entry when I am done.

1 Comments:

  • Interesting approach. However you might want to use a ReaderWriterLock to allow multiple readers at the same time.

    (http://msdn2.microsoft.com/library/system.threading.readerwriterlock.aspx)

    By Blogger Hoop, at 3:35 PM  

Post a Comment

<< Home