Releasing a Mutex

11,024

You are not handling the case whereby the mutex.WaitOne returns false ie times out. If WaitOne returns false you don't own the mutex therefore you don't need to release it.

bool iOwnTheMutex;

try {
    // set up mutex here...
    iOwnTheMutex = mutex.WaitOne(2000);
    if (iOwnTheMutex) {
       // do what you need to do
    }
}
finally {
    if (mutex != null && iOwnTheMutex) {
       mutex.ReleaseMutex();
    }
}    
Share:
11,024
Neilski
Author by

Neilski

Updated on July 27, 2022

Comments

  • Neilski
    Neilski almost 2 years

    I have a web application that needs to utilise an application cache to store data (due to the high overhead of obtaining that data ona request by request basis). See previous post at https://stackoverflow.com/a/16961962/236860

    This approach seems to work well, but I am seeing the following occasional errors in the web site's error:

    System.ApplicationException: Object synchronization method was called from an
    unsynchronized block of code.
    at System.Threading.Mutex.ReleaseMutex()
    at InboxInsight.Web.Web_Controls.Twitter.TwitterFeed.GetTwitterData(HttpContext context)
    at InboxInsight.Web.Web_Controls.Twitter.TwitterFeed.ProcessRequest(HttpContext context)
    at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
    at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
    

    For reference, here is the code block:

    public string GetData(HttpContext context)
    {
        var cache      = context.Cache;
        Mutex mutex    = null;
        string data    = (string)cache[CacheKey];
    
        // 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(true, CacheKey);
    
               // Wait until it is safe to enter (someone else might already be
               // doing this), but also add 30 seconds max.
               mutex.WaitOne(30000);
    
               // Now let's see if some one else has added it...
               data = (string)cache[CacheKey];
    
               // They did, so send it...
               if (data != null)
               {
                  return data;
               }
    
    
               // Still not there, so now is the time to look for it!
               data = GetSlowFeed(context);
    
               cache.Remove(CacheKey);
               cache.Add(CacheKey, data, null, GetExpiryDate(),
                  TimeSpan.Zero, CacheItemPriority.Normal, null);
           }
           finally
           {
               // Release the Mutex.
               if (mutex != null)
               {
                  mutex.ReleaseMutex();
               }
           }
        }
    
        return data;
    }
    

    From what I have researched, it suggests this problem is caused by a process thread trying to release a Mutex that it didn't create, but I don't understand how this could happen.

    Can anyone suggest how I can re-structure the code to avoid this problem?

    • NotMe
      NotMe almost 11 years
      I added a comment to your other question. However it's probably appropriate here as well. There are existing caching providers for asp.net. AppFabric is one, Memcached is another. Both are very good at what they do. To the point that I wouldn't bother rolling my own.
    • Neilski
      Neilski almost 11 years
      Hi Chris, thanks for the suggestion. I have now looked at AppFabric and Memcached, but they do not seem to be suitable for my application as it is running in a shared hosting environment. As distributed cache applications I believe these both need to be installed at the server/OS level which, unfortunately, precludes their use in this application.
  • Randall Becker
    Randall Becker over 10 years
    This answer no longer works in Metro apps. The exception still occurs consistently, even in the test case, if iOwnTheMutex is true. I have been able to recreate with one thread (UI) taking/releasing the mutex, while a separate thread (non-UI) takes the mutex and is unable to release it, with no other threads attempting to take it.
  • Jack Hughes
    Jack Hughes over 10 years
    The Mutex's main selling point is synchronising between processes. Sounds like you are synchronising within a process. I'm sure you can find something more suitable for that like, at the simplest, the lock keyword in C#.
  • Matt Wilko
    Matt Wilko about 8 years
    I don't think this is a safe solution because a bool is not thread safe
  • Jack Hughes
    Jack Hughes about 8 years
    iOwnTheMutex is a local variable, no other thread / process would be able to access it.
  • user626528
    user626528 about 6 years
    Checking if the mutex is owned and then trying to release it later - there is a race condition in here.