Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Releasing a Mutex

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?

like image 910
Neilski Avatar asked Jun 12 '13 16:06

Neilski


People also ask

Does disposing a mutex release it?

With a Mutex class, you call the WaitHandle. WaitOne method to lock and ReleaseMutex to unlock. Closing or disposing a Mutex automatically releases it.

How do you stop mutex?

Generally, CLI objects don't need deletion, because the platform is managed. But with Mutex , you need to call IDisposable. Dispose() when this object is no longer needed, and this interface method is implemented by System.

What is an abandoned mutex?

An abandoned mutex indicates a serious programming error.

What does mutex acquire do?

Mutex is a synchronization primitive that grants exclusive access to the shared resource to only one thread. If a thread acquires a mutex, the second thread that wants to acquire that mutex is suspended until the first thread releases the mutex.


1 Answers

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();
    }
}    
like image 141
Jack Hughes Avatar answered Oct 19 '22 06:10

Jack Hughes