在 finally 块中释放时出现 AbandonedMutexException
AbandonedMutexException while releasing in finally block
我有一个在缓存中存储大型列表的应用程序。为了防止多个用户同时填充此缓存,我使用了 Mutex。但是,我偶尔会遇到错误:
System.Threading.AbandonedMutexException: The wait completed due to an abandoned mutex.
您可能会争辩说我忘记释放 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: 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)
您应该使用单个互斥锁,而不是为每个函数调用声明一个新的互斥锁。也许在 class 这个函数所在的范围内声明一个静态互斥锁,并根据需要声明 wait/release 。查看此页面上的示例:
https://docs.microsoft.com/en-us/dotnet/api/system.threading.mutex?view=netframework-4.7.2
我有一个在缓存中存储大型列表的应用程序。为了防止多个用户同时填充此缓存,我使用了 Mutex。但是,我偶尔会遇到错误:
System.Threading.AbandonedMutexException: The wait completed due to an abandoned mutex.
您可能会争辩说我忘记释放 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: 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)
您应该使用单个互斥锁,而不是为每个函数调用声明一个新的互斥锁。也许在 class 这个函数所在的范围内声明一个静态互斥锁,并根据需要声明 wait/release 。查看此页面上的示例:
https://docs.microsoft.com/en-us/dotnet/api/system.threading.mutex?view=netframework-4.7.2