I have an application that stores large lists in cache. To prevent several users to fill this cache at the same time, I am using a Mutex. However, I get occasional errors:
System.Threading.AbandonedMutexException: The wait completed due to an abandoned mutex.
You would argue that I forgot to release the Mutex but the release is in a Finally block so it should always release it. How can the code below cause a AbandonedMutexException? The 'mutex.ReleaseMutex' is supposed to be fired always.
public static List<Objects.SearchListItem> GetActiveCwPropertyListItemsByCwPropertyAndCulture(CwProperty cwProperty, string cultureCode)
{
var cacheKey = "GetActiveCwPropertyListItemsByCwPropertyAndCulture_" + cwProperty.Guid + "_" + cultureCode;
var mutex = new Mutex(true, cacheKey);
mutex.WaitOne();
try
{
var cachedValue = HttpRuntime.Cache[cacheKey];
if (cachedValue != null) return (List<Objects.SearchListItem>)cachedValue;
var value = new List<Objects.SearchListItem>();
var dr = new CwDbAccess(System.Data.CommandType.StoredProcedure, "CwPropertyListItemPart_LoadByCwProperty");
try
{
dr.ExecuteReader();
while (dr.MyReader.Read())
{
value.Add(new Objects.SearchListItem
{
Name = Utils.ProperCase(dr.MyReader["Name"].ToString()),
Key = dr.MyReader["CwPropertyListItem_Guid"].ToString(),
IsAlias = false
});
}
}
catch (Exception ex)
{
CwLogging.LogException("Caching.ListItems.GetActiveCwPropertyListItemsByCwPropertyAndCulture", ex, ExceptionLevel.Urgent);
}
finally
{
dr.Close();
}
var keys = new List<string>();
AddDependency("CwSiteClusterKey_" + cwProperty.CachedCwEntity.CwSiteClusterGuid, keys);
AddDependency("CwPropertyKey_" + cwProperty.Guid, keys);
HttpRuntime.Cache.Insert(cacheKey, value, new CacheDependency(null, keys.ToArray()), Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Default, null);
return value;
}
catch
{
throw;
}
finally
{
mutex.ReleaseMutex();
}
}
The full stacktrace is:
System.Threading.AbandonedMutexException: The wait completed due to an abandoned mutex. at System.Threading.WaitHandle.ThrowAbandonedMutexException() at System.Threading.WaitHandle.InternalWaitOne(SafeHandle waitableSafeHandle, Int64 millisecondsTimeout, Boolean hasThreadAffinity, Boolean exitContext) at System.Threading.WaitHandle.WaitOne(Int32 millisecondsTimeout, Boolean exitContext) at Common.Caching.ListItems.GetActiveCwPropertyListItemsByCwPropertyAndCulture(CwProperty cwProperty, String cultureCode) at Model.SearchFacet.GetAllSearchListItems(CwContext cwContext) at Common.Search.SqlFacets.RetrieveSqlFacetsByGroup(CwEntity cwEntity, NameValueCollection storedRequestForm, SqlFacetsContainer sqlFacets, SearchFacetGroupCollection groups, SearchTemplate searchTemplate, CwContext cwContext) at Common.Search.SqlFacets.RetrieveSqlFacets(CwEntity cwEntity, NameValueCollection storedRequestForm, CwContext cwContext, SearchResultViewType searchResultViewType) at Common.Caching.SqlFacets.GetSqlFacets(String hash, NameValueCollection storedRequestForm, CwEntity cwEntity, CwContext cwContext, SearchResultViewType searchResultViewType) at Compareware_WebApp.Ui.Pages.SearchPage.AppendSearchAndResults(StringBuilder sb) in C:\Projects\Compareware\Compareware.WebApp\Ui\Pages\SearchPage.cs:line 454 at Compareware_WebApp.Ui.Pages.SearchPage.get_MainContent() in C:\Projects\Compareware\Compareware.WebApp\Ui\Pages\SearchPage.cs:line 310 at ASP.default_aspx.__RenderContent2(HtmlTextWriter __w, Control parameterContainer) at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) at ASP.masters_site_master.__RenderForm1(HtmlTextWriter __w, Control parameterContainer) at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) at System.Web.UI.HtmlControls.HtmlForm.RenderChildren(HtmlTextWriter writer) at System.Web.UI.HtmlControls.HtmlContainerControl.Render(HtmlTextWriter writer) at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) at System.Web.UI.HtmlControls.HtmlForm.RenderControl(HtmlTextWriter writer) at ASP.masters_site_master.__RenderBody(HtmlTextWriter __w, Control parameterContainer) at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) at System.Web.UI.HtmlControls.HtmlContainerControl.Render(HtmlTextWriter writer) at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) at ASP.masters_site_master.__Render__control1(HtmlTextWriter __w, Control parameterContainer) at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) at System.Web.UI.Page.Render(HtmlTextWriter writer) at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
true
everytime. What if two threads create two mutexes at the same time, who's the owner? These are just vague observations TBF – Liam