fix: resolve UnloadAllAssetsOperation deadlock when releasing zero-ref pending providers

This commit is contained in:
何冠峰
2026-06-02 14:21:18 +08:00
parent 20ae423bbe
commit a5f4b555e7
2 changed files with 42 additions and 0 deletions

View File

@@ -25,6 +25,7 @@ namespace YooAsset
CheckOptions, CheckOptions,
ReleaseAll, ReleaseAll,
TryAbortLoader, TryAbortLoader,
RequestForceDestroy,
CheckLoading, CheckLoading,
DestroyAll, DestroyAll,
Done, Done,
@@ -93,6 +94,17 @@ namespace YooAsset
{ {
loader.TryAbortLoader(); loader.TryAbortLoader();
} }
_steps = ESteps.RequestForceDestroy;
}
if (_steps == ESteps.RequestForceDestroy)
{
// 向所有资源提供者下发强制销毁请求
// 注意:防止零引用且尚未进入加载阶段的任务被无限挂起,从而导致 CheckLoading 死锁。
foreach (var provider in _resManager.ProviderDic.Values)
{
provider.RequestForceDestroy();
}
_steps = ESteps.CheckLoading; _steps = ESteps.CheckLoading;
} }

View File

@@ -67,6 +67,11 @@ namespace YooAsset
/// </summary> /// </summary>
public bool IsDestroyed { private set; get; } = false; public bool IsDestroyed { private set; get; } = false;
/// <summary>
/// 是否已收到强制销毁请求
/// </summary>
public bool ForceDestroyRequested { private set; get; } = false;
/// <summary> /// <summary>
/// 加载任务是否进行中 /// 加载任务是否进行中
/// </summary> /// </summary>
@@ -119,6 +124,18 @@ namespace YooAsset
if (_steps == ESteps.None || _steps == ESteps.Done) if (_steps == ESteps.None || _steps == ESteps.Done)
return; return;
// 注意:收到强制销毁请求时,未在加载中的任务立即结束,防止零引用任务被无限挂起导致卸载流程死锁!
if (ForceDestroyRequested)
{
if (IsLoading == false)
{
InvokeCompletion("Provider force destroyed during unload all assets !", EOperationStatus.Failed);
return;
}
// 注意:已进入加载阶段则继续等待自然完成
}
// 注意:未在加载中的任务可以挂起! // 注意:未在加载中的任务可以挂起!
if (IsLoading == false) if (IsLoading == false)
{ {
@@ -199,11 +216,24 @@ namespace YooAsset
} }
protected abstract void ProcessBundleResult(); protected abstract void ProcessBundleResult();
/// <summary>
/// 请求强制销毁
/// 注意:用于卸载流程,标记后未在加载中的任务会在下一次更新时立即结束。
/// </summary>
public void RequestForceDestroy()
{
ForceDestroyRequested = true;
}
/// <summary> /// <summary>
/// 销毁资源提供者 /// 销毁资源提供者
/// 注意:该方法是幂等的,重复调用不会重复释放资源。
/// </summary> /// </summary>
public void DestroyProvider() public void DestroyProvider()
{ {
if (IsDestroyed)
return;
IsDestroyed = true; IsDestroyed = true;
// 检测是否为正常销毁 // 检测是否为正常销毁