Jan272009

lock(string) deadlock, and interning

In one of my applications, one of the database (Oracle Server), started responding very slowly which was causing timeout errors on the browser. I decided to cache the data, so i wrote this:

   1: HttpContext.Current.Cache.Add("dtUsers", dtUsers, null, DateTime.Now.AddDays(2), 
   2: TimeSpan.Zero,System.Web.Caching.CacheItemPriority.Normal, null);


The above code is simply putting the database into the cache.I read in so many different places that System.Web.Cache is thread safe; however still i decided to put a lock mechanism to make sure, only 1 instance can access to cache, as there is only 1 item in the cache (which is the datatable), and all other threads will be reading/writing to this. So i read about lock in ASP.NET, and i wrote the below code:

   1: DataTable dtUsers = null;
   2: if (HttpContext.Current.Cache["dtUsers"] != null)
   3:     {
   4:         return (HttpContext.Current.Cache["dtUsers"] as DataTable).Copy().DefaultView;
   5:     }
   6:     lock (CacheSyncObject)
   7:     {          
   8:         if (HttpContext.Current.Cache["dtUsers"] != null)
   9:         {           
  10:             return (HttpContext.Current.Cache["dtUsers"] as DataTable).
  11:                 Copy().DefaultView;
  12:             }
  13:             dtUsers = OnlineDirectoryAccess.GetUsers();
  14:             HttpContext.Current.Cache.Add("dtUsers", dtUsers, null, 
  15:                 DateTime.Now.AddDays(2), TimeSpan.Zero,
  16:                 System.Web.Caching.CacheItemPriority.Normal, null);
  17:             return (HttpContext.Current.Cache["dtUsers"] as DataTable).Copy().DefaultView;
  18:         }

The lock object CacheSyncObject was a string object i created as a static variable, so that simple code was:

   1: public static string CacheSyncObject = "CacheSync";

Everything was working in my local, however when i deployed the project, the web application stopped working, and got timeout errors. I put some logs to see when it hang, and apparently at the lock() statement, the system was frozen. There was a deadlock in the system, after so many reading, and asking questions in the forums, i got my answer :) and i want to share it now :)

.NET Framework uses string interning to store strings. You can see the definition of this at wikipedia. Basically for performance issues, framework is storing only 1 copy of each distinct string value in the memory. By this way, same copy of string is shared between threads and different AppDomains. This also brings the issue of not being able have too much control over the strings. For this reason we should not put locks on string objects as other threads have still access to the same memory address.

The solution was very simple:

   1: public static object CacheSyncObject = new object();


Tags:

E-mail | Permalink | Trackback | Post RSSRSS comment feed 0 Responses

Add comment