多线程动画计算的过程时,在FSkeletonRemapping::RetargetBoneRotationToTargetSkeleton函数中,发生了崩溃

崩溃调用栈:

[Image Removed]

对应的日志:

[Image Removed]

目前看逻辑,猜测的原因

1.主线程序列化,执行了RegenerateMapping逻辑,并执行“RetargetingTable.Reset()”,对RetargetingTable进行了清理

[Image Removed]

2.多线程动画线程中,获取了“const FSkeletonRemapping& SkeletonRemapping”,并在后面的逻辑中,会访问RetargetingTable

[Image Removed]

3.多线程动画线程中对RetargetingTable进行了访问。猜测是多线程读写问题导致的崩溃。请问是否合理?

[Image Removed]

Hi,

你好,这个问题可能已经修复了,可以试一下这个改动

https://github.com/EpicGames/UnrealEngine/commit/22cf2228c7756f06a851b29318e1c2091f7b7c1b

嗨,你好。试过了,仍然崩溃。

目前写了一堆伪代码,强制把动画线程序列化线程的一些关键函数的时间线对齐后,就能必现这个多线程读写问题。对USkeletalMesh::Serialize疑点比较大,为啥序列化骨骼模型的时候,要执行“UE::Anim::FSkeletonRemappingRegistry::Get().RefreshMappings(Skeleton);”​

USkeletalMesh::Serialize()

{

if (Ar.IsLoading())

{

const bool bRebuildNameMap = false;

GetRefSkeleton().RebuildRefSkeleton(GetSkeleton(), bRebuildNameMap); // 这个函数内部会调用UE::Anim::FSkeletonRemappingRegistry::Get().RefreshMappings

}

}​

比如,Base-Skel是基础骨架,A-Skel是映射到Base-Skel的骨架。A1,A2,A3​,A4等骨骼模型(USkeletalMesh)使用的是骨架A-Skel。

加载A1骨骼模型时,会触发​UE::Anim::FSkeletonRemappingRegistry::Get().RefreshMappings

加载A2骨骼模型时,会再次触发UE::Anim::FSkeletonRemappingRegistry::Get().RefreshMappings

加载Axxx骨骼模型时,都会触发UE::Anim::FSkeletonRemappingRegistry::Get().RefreshMappings

不确定,是否合理?​

Hi,

感谢提供信息,我觉得的确是有这个情况发生的,​我已经提了一个jira UE-353766, 把信息反馈到里面了,可以等后续修复。

嗨,想问下,这个崩溃bug已经修复了吗?或者能提供一些修改思路吗?

Hi,

不好意思,暂时还没有修复。

问题其实本质上很简单,就是FSkeletonRemappingRegistry::GetRemapping 返回的是引用,理论上应该要保证这个引用使用完以前,不能修改这个引用的数据,但是因为锁是加在函数内的,所以在函数返回的时候,锁就unlock了,导致引用数据还在被使用,同时FSkeletonRemappingRegistry::RefreshMappings也可以被执行。

所以最安全的做法,就是把GSkeletonRemappingRegistry->MappingsLock放到所有使用GetRemapping的地方。或者只让GetRemapping返回拷贝而不是引用。

不过最终修复,还要等开发的同学决定。