Deadlock between GameThread and FAsyncLoadingThread inUPropertyBag::GetOrCreateFromDescs

Deadlock reports from users: GameThread invokes UPCGSettings::PostLoad, ending up in UPropertyBag::GetOrCreateFromDescs at the same time as FAsyncLoadingThread. The latter already holds “FUObjectHashTables” from earlier in the stack.

[Attachment Removed]

Steps to Reproduce[Attachment Removed]

Hi Vincent!

If you have repro steps, or at least some more context (stacks, …) that would be great!

I’m not aware of issues like this before, but Adrien might know & can have a look.

Cheers,

Julien

[Attachment Removed]

Thanks for your answer!

I did paste the stacks in the the relevant section of the form, but I will also do it as a comment for search convenience. Here are the details:

--- GameThread stack:

StaticFindObjectFastInternalThreadSafe    // Requests "FUObjectHashTables"
UPropertyBag::GetOrCreateFromDescs    // Holds "GPropertyBagLock"
UPCGSettings::InitializeOverriddenSettingsPropertyBag
UPCGSettings::PostLoad
... (deferred PostLoad)
FlushAsyncLoading UWorld::FlushLevelStreaming
UEngine::LoadMap

--- FAsyncLoadingThread stack:

UPropertyBag::GetOrCreateFromDescs    // Requests "GPropertyBagLock"
FInstancedPropertyBag::Serialize
UObject::Serialize FLinkerLoad::Preload
USCS_Node::PreloadChain
UBlueprintGeneratedClass::FindArchetype    // Holds "FUObjectHashTables"
FindArchetypeFromRequiredInfoImpl
UObject::GetArchetypeFromRequiredInfo
FLinkerLoad::CreateExport

Temporary fix in our codebase: replace PostLoad invocation of “UPCGSettings::InitializeOverriddenSettingsPropertyBag”, whose single purpose is to fill “OverriddenSettingsPropertyBag”, by lazy initialization in “CreateEmptyPropertyBagInstance”, the single one place where “OverriddenSettingsPropertyBag” is read.

[Attachment Removed]

Hi Vincent!

Indeed this is a clear issue of deadlock, which probably arose in 5.7 because we pushed more async loading.

If you have repro steps this would help a lot, since those are nasty to debug.

Also would you be able to give more info on your setup?

The async loading thread is stuck while loading a property bag on a blueprint class (USCS_Node would indicate a property bag on a component).

It would help to know where this Property bag comes from (and if it is valid to have it there).

Thanks!

Adrien

[Attachment Removed]

Hi Adrien,

Claude helped identify the problematic assets in our game. Here is its summary with recommended repro steps:

Setup: UE 5.7, Windows, client build.

Trigger: deadlock occurs during level streaming — a sublevel is loaded asynchronously while gameplay is running.

Repro steps:

  1. Create a Blueprint actor class with a UPCGComponent added via the SimpleConstructionScript (the Components panel in the Blueprint editor, not spawned at runtime).
  2. Assign a UPCGGraph to the component. The graph should have at least one settings node with overridable parameters so that InitializeOverriddenSettingsPropertyBag has work to do during PostLoad.
  3. On placed instances of that Blueprint actor in a sublevel, set per-instance PCG graph parameter overrides (ParametersOverrides / FPCGOverrideInstancedPropertyBag) on the component.
  4. Stream that sublevel in asynchronously while the game is running.

Source of the FInstancedPropertyBag: FPCGOverrideInstancedPropertyBag::Parameters inside UPCGGraphInstance::ParametersOverrides (stock PCG plugin, PCGGraph.h).

[Attachment Removed]

Hey Vincent,

Thanks for the additional info. We’ve submitted a fix which takes the lazy initialization as you suggested! Available here: https://github.com/EpicGames/UnrealEngine/commit/46fea5d67c84bc2a31310789849a44de5fc9ddb8

Cheers,

Wyatt

[Attachment Removed]