Releasing a Mutex
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();
}
}
Neilski
Updated on July 27, 2022Comments
-
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 almost 11 yearsI 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 almost 11 yearsHi 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 over 10 yearsThis 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 over 10 yearsThe 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 about 8 yearsI don't think this is a safe solution because a bool is not thread safe
-
Jack Hughes about 8 years
iOwnTheMutex
is a local variable, no other thread / process would be able to access it. -
user626528 about 6 yearsChecking if the mutex is owned and then trying to release it later - there is a race condition in here.