异步提交:WeakObjectPtr 防崩溃,不证明结果仍有效
自动关联目录:异步提交:WeakObjectPtr 防崩溃,不证明结果仍有效
核心判断:弱引用只能回答 UObject 还在不在;异步结果能否提交,还必须证明它仍属于当前 World、对象代次、属性槽和用户意图。
一、业务冲突
资产、声音、图片、碰撞和动画都可能异步完成。对象未销毁并不表示请求仍有效:同一对象可能已经改了资源、退出 Play、换了 World,甚至用相同逻辑 ID 重建为新实例。只检查 WeakThis.IsValid(),旧结果仍会覆盖新状态。
二、实际实现
工程中已经出现多种正确的第二道门:资源加载在回调中检查请求 ID 仍处于 Pending;声音同时校验 ObjectId、资源身份与递增 LoadGeneration;图片使用节点请求令牌;物理接触异步工作保存状态 Revision;VM 回调绑定运行域 Generation。提交前再回到 Game Thread,确认目标和请求仍匹配。
三、值得保留
“弱引用 + 业务代次”是正确方向。弱引用保护内存安全,代次保护语义安全;两者职责没有混淆。按属性槽生成令牌也比整对象只有一个 Generation 更精确,不会因加载图片而无谓取消声音。
四、结构性缺陷
每个子系统都在重新发明 RequestToken、Generation、Pending Map 和清理顺序。它们的作用域有的是 World,有的是对象,有的是属性;数值类型和失效规则不统一。多数实现能拒绝迟到提交,却不一定能取消底层下载、释放共享需求或记录取消原因,因此“结果没写错”不等于“资源成本已停止”。
五、目标设计
提供层级化 OperationScope,将取消传播和提交证明分开:
struct CommitPermit {
SessionId session;
WorldGeneration world;
ObjectGeneration object;
SlotRevision slot;
RequestId request;
};
auto ticket = assets.Prepare(ref, scope.Child(object, slot));
ticket.OnReady([permit](PreparedAsset value) {
GameThread::Enqueue([permit, value = MoveTemp(value)] {
if (!scopes.CanCommit(permit)) return;
projectors.Commit(permit, value);
});
});Scope 关闭时先撤销提交权,再向可取消后端传播 Cancel;不可取消工作允许完成,但只能释放 Prepared 结果,不能触碰业务对象。
六、取舍与验证
统一 Scope 会增加适配成本,共享下载还要区分“取消一个需求”和“取消物理任务”。测试必须覆盖同对象连续换资源、删除后同 ID 重建、World teardown、Play 重启、请求合并后一方取消、完成与取消同帧竞争,以及不可取消任务最终释放。核心不变量是:任何提交都能指出自己依赖的全部当前身份。