Thursday, September 16, 2010

USING APPDOMAINS TO MAKE NON-THREADSAFE CODE THREADSAFE

Recently, I was involved in a Wintellect consulting engagement where a customer had some class library code that was created years ago. The code in this class library was not designed to work well in a multithreaded environment. Specifically, this means that if two or more threads called into the class library code at the same time, the data got corrupted and the results could not be trusted. Non-concurrent-ready code is easy to obtain with frequent use of mutable static fields. But, there are other common coding practices which can result in code that is not safe with multiple threads passing through it at the same time.
This customer wanted to increase the performance of their code and the best way to accomplish this is to have multiple threads processing their own data independently of each other. But, again, the class library code base would produce errant results if we did this. To demonstrate the problem, imagine this very simple static class which is indicative of the non-thread safe class library that I'm referring to:
internal static class NonConcurrentAlgorithm
{

private static List<String> s_items = new List<String>();
public static void Add(String item) { s_items.Add(item); }
public static String[] GetItems() { return s_items.ToArray(); }
}
If we have two threads using this class simultaneously, the results are unpredictable. For example, let's say we have this code:
ThreadPool.QueueUserWorkItem(o => NonConcurrentAlgorithm.Add("Item 1"), null);
NonConcurrentAlgorithm.Add("Item 2");
Thread.Sleep(1000);  // To demonstrate the problem consistently
foreach (var i in NonConcurrentAlgorithm.GetItems())
  Console.WriteLine(i);
When this code runs, the console could show:
"Item 2" by itself
"Item 2" followed by "Item 1"
"Item 1" followed by "Item 2"
Clearly, this is not desireable and the problem all stems from the threads sharing the one List<String> object. In fact, the List<T> class is not itself thread-safe and so it is even possible that having multiple threads accessing it simultaneously could result in items disappearing or a single item being inserted multiple times, or worse. It depends on how the List<T> class is internally implemented which is not documented and is subject to change.
Read more: JEFFREY RICHTER'S BLOG