AbandonedMutexException при выпуске в блоке finally - PullRequest
0 голосов
/ 16 ноября 2018

У меня есть приложение, которое хранит большие списки в кеше. Чтобы не допустить одновременного заполнения этого кэша несколькими пользователями, я использую Mutex. Тем не менее, я получаю случайные ошибки:

System.Threading.AbandonedMutexException: ожидание завершено из-за брошенного мьютекса.

Вы могли бы утверждать, что я забыл выпустить Mutex, но выпуск находится в блоке finally, поэтому он всегда должен выпускать его. Как приведенный ниже код может вызвать исключение AbandonedMutexException? 'Mutex.ReleaseMutex' должен запускаться всегда.

    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();
    }
}

Полная трассировка стека:

System.Threading.AbandonedMutexException: ожидание завершено из-за оставленного мьютекса. в System.Threading.WaitHandle.ThrowAbandonedMutexException () в System.Threading.WaitHandle.InternalWaitOne (SafeHandle waitableSafeHandle, Int64 миллисекундыTimeout, логическое значение hasThreadAffinity, логическое значение exitContext) в System.Threading.WaitHandle.WaitOne (Int32 миллисекундTimeout, логическое значение exitContext) в Common.Caching.ListItems.GetActiveCwPropertyListItemsByCwPropertyAndCulture (CwProperty cwProperty, String cultureCode) в Model.SearchFacet.GetAllSearchListItems (CwContext cwContext) в Common.Search.SqlFacets.RetrieveSqlFacetsByGroup (CwEntity cwEntity, NameValueCollection selectedRequestForm, SqlFacetsContainer sqlFacets, группы SearchFacetGroupCollection, SearchTemplate searchTemplate, CwConxtxtw) в Common.Search.SqlFacets.RetrieveSqlFacets (CwEntity cwEntity, NameValueCollection StoreRequestForm, CwContext cwContext, SearchResultViewType searchResultViewType) в Common.Caching.SqlFacets.GetSqlFacets (Строковый хеш, NameValueCollection selectedRequestForm, CwEntity cwEntity, CwContext cwContext, SearchResultViewType searchResultViewType) в Compareware_WebApp.Ui.Pages.SearchPage.AppendSearchAndResults (StringBuilder sb) в C: \ Projects \ Compareware \ Compareware.WebApp \ Ui \ Pages \ SearchPage.cs: строка 454 в Compareware_WebApp.Ui.Pages.SearchPage.get_MainContent () в C: \ Projects \ Compareware \ Compareware.WebApp \ Ui \ Pages \ SearchPage.cs: строка 310 в ASP.default_aspx .__ RenderContent2 (HtmlTextWriter __w, управляющий параметрContainer) в System.Web.UI.Control.RenderChildrenInternal (автор HtmlTextWriter, дети ICollection) в System.Web.UI.Control.RenderControlInternal (средство записи HtmlTextWriter, адаптер ControlAdapter) в System.Web.UI.Control.RenderChildrenInternal (автор HtmlTextWriter, дети ICollection) в System.Web.UI.Control.RenderControlInternal (средство записи HtmlTextWriter, адаптер ControlAdapter) на ASP.masters_site_master .__ RenderForm1 (HtmlTextWriter __w, управляющий параметрContainer) в System.Web.UI.Control.RenderChildrenInternal (автор HtmlTextWriter, дети ICollection) в System.Web.UI.HtmlControls.HtmlForm.RenderChildren (писатель HtmlTextWriter) в System.Web.UI.HtmlControls.HtmlContainerControl.Render (писатель HtmlTextWriter) в System.Web.UI.Control.RenderControlInternal (средство записи HtmlTextWriter, адаптер ControlAdapter) в System.Web.UI.HtmlControls.HtmlForm.RenderControl (писатель HtmlTextWriter) в ASP.masters_site_master .__ RenderBody (HtmlTextWriter __w, управляющий параметрContainer) в System.Web.UI.Control.RenderChildrenInternal (автор HtmlTextWriter, дети ICollection) в System.Web.UI.HtmlControls.HtmlContainerControl.Render (писатель HtmlTextWriter) в System.Web.UI.Control.RenderControlInternal (средство записи HtmlTextWriter, адаптер ControlAdapter) на ASP.masters_site_master .__ Render__control1 (HtmlTextWriter __w, управляющий параметрContainer) в System.Web.UI.Control.RenderChildrenInternal (автор HtmlTextWriter, дети ICollection) в System.Web.UI.Control.RenderControlInternal (средство записи HtmlTextWriter, адаптер ControlAdapter) в System.Web.UI.Control.RenderChildrenInternal (автор HtmlTextWriter, дети ICollection)в System.Web.UI.Control.RenderControlInternal (средство записи HtmlTextWriter, адаптер ControlAdapter) в System.Web.UI.Control.RenderChildrenInternal (автор HtmlTextWriter, дети ICollection) в System.Web.UI.Page.Render (писатель HtmlTextWriter) в System.Web.UI.Control.RenderControlInternal (средство записи HtmlTextWriter, адаптер ControlAdapter) в System.Web.UI.Page.ProcessRequestMain (логическое значение includeStagesBeforeAsyncPoint, логическое значение includeStagesAfterAsyncPoint)

1 Ответ

0 голосов
/ 16 ноября 2018

Вы должны использовать один мьютекс вместо того, чтобы объявлять новый мьютекс для каждого вызова функции. Возможно, объявите статический мьютекс в области видимости класса, в котором находится эта функция, и при необходимости ожидайте / освобождайте. Проверьте пример на этой странице:

https://docs.microsoft.com/en-us/dotnet/api/system.threading.mutex?view=netframework-4.7.2

...