0

I am trying to write a custom mechanism for compressing and caching web scripts. I am using a Mutex to provide managed access for the cache creation methods.

public class HttpApplicationCacheManager
{

  public object Get(
     Cache cache,   // Reference to the HttpContext.Cache
     string key,    // Id of the cached object
     int retrievalWaitTime,
     Func<object> getData,  // Method that builds the string to be cached
     Func<CacheDependency> getDependency)  // CacheDependency object for the 
                                           // string[] of file paths to be cached
  {
     Mutex mutex = null;
     bool iOwnMutex = false;
     object data = cache[key];

     // Start check to see if available on cache
     if (data == null)
     {
        try
        {
           // Lock base on resource key
           // (note that not all chars are valid for name)
           mutex = new Mutex(false, key);

           // Wait until it is safe to enter (someone else might already be
           // doing this), but also add 30 seconds max.

           iOwnMutex = mutex.WaitOne(retrievalWaitTime * 1000);

           // Now let's see if some one else has added it...
           data = cache[key];

           // They did, so send it...
           if (data != null)
           {
              return data;
           }

           // Still not there, so now is the time to look for it!
           data = getData();
           var dependency = getDependency();
           cache.Insert(key, data, dependency);
        }
        catch
        {
           throw;
        }
        finally
        {
           // Release the Mutex.
           if ((mutex != null) && (iOwnMutex))
           {
              mutex.ReleaseMutex();
           }
        }
     }

     return data;
  }
}

The

Whilst this works, I occasionally see the following error:

System.UnauthorizedAccessException 
   Access to the path 'SquashCss-theme.midnight.dialog' is denied.

I have found some posts suggesting that this might be due to a race condition. Unfortunately, my Mutex knowledge is very limited and I am struggling to see where the problem might be.

Any help would be much appreciated.

Neilski
  • 4,385
  • 5
  • 41
  • 74
  • http://stackoverflow.com/questions/19536697/unauthorizedaccessexception-when-trying-to-open-a-mutex – David Aug 04 '14 at 16:44
  • I looked at http://stackoverflow.com/q/19536697/236860, but I ran into a problem when I tried to modify my code as when I tried to release the Mutex, I received an error relating to trying to release Mutex in unsynchronised code. – Neilski Aug 04 '14 at 17:02
  • it seems you've had this issue before [Previous Issue](http://stackoverflow.com/questions/17070583/releasing-a-mutex) when releasing locks that aren't from the correct thread. If this is your intent then Semaphores could be an option. As for what I see why doesn't a simple Lock(){ //code here } work here – David Aug 04 '14 at 17:44
  • I have indeed had this problem before - unfortunately the previous solution, or at least my implementation/interpretation of it, does not seem to work here - hence my confusion over the second error. The reason I chose to use a Mutex is because the getData() function call can be quite slow (several seconds) and I *thought* a Mutex was better suited. Fundamentally, I don't have a good understanding of multi-threading in general so I am not sure about either my decisions or my implementation of those decisions. Thanks for your patience. – Neilski Aug 04 '14 at 20:30

1 Answers1

0

Why not just use any of the built-in .NET caches? I don't see anything in your code that could not be handled by the .NET cache implementations. Another option maybe the readerwriterlockslim class, since you really only need to lock on writes.

AceCTO
  • 1
  • 1
  • 1
  • I am building this module over a legacy CSS and JavaScript bundling 'engine' which simply provides a mechanism for rendering groups of files on the ASP.net page. As the site has grown, there are now perhaps hundreds of script fragments - none of these are compressed and are currently rendered as individual items. The idea is to, on-demand, read the bundles, combine and then compress them into a (far) fewer number of compresses files. The reason for the Mutex is to avoid the overhead of reading, combining and compressing the same bundles multiple times. Once created, the files are cached. – Neilski Aug 04 '14 at 17:33
  • That is a worthy goal, just be careful of ordering. If the old engine placed everything in order on the page at one location you should be ok. If it placed files at different locations on the page it is possible to break everything if you change the order by combining. In regards to the orig question, I would still use the standard asp.net output cache or the .NET cache, rather than building my own. There doesn't appear to be any business value in DIY. – AceCTO Aug 04 '14 at 17:54
  • Thank you. Luckily the existing 'engine' does provide sequencing control and also uses a common placeholder to insert the results onto the page. Ap[art from the error, the rest of the fix (as that is all it can be at this stage) is working much better than expected, but not well enough if it crashes, albeit infrequently. The fix does use the HttpContext.Cache by preference, the compressed files are persisted on disk. – Neilski Aug 04 '14 at 20:33