I was sure you were wrong about this, but I ran a test:
uint32 AMyActor::Runnable::Run()
{
uint32 ThreadId = FPlatformTLS::GetCurrentThreadId();
FString ThreadName = FThreadManager::Get().GetThreadName(ThreadId);
UE_LOG(LogTemp, Warning, TEXT("background thread name %s"), *ThreadName);
Delegate.BindLambda(](){
uint32 ThreadId = FPlatformTLS::GetCurrentThreadId();
FString ThreadName = FThreadManager::Get().GetThreadName(ThreadId);
UE_LOG(LogTemp, Warning, TEXT("delegate callback in thread name %s"), *ThreadName);
});
Delegate.Execute();
return 0;
}
A background thread launched on BeginPlay, which binds and fires a delegate in the thread. The output:
[2019.08.26-17.33.31:279][839]LogTemp: Warning: background thread name BgThread
[2019.08.26-17.33.31:279][839]LogTemp: Warning: delegate callback in thread name BgThread
So it appears you’re right…I was assuming that the delegates themselves put themselves on a queue when they Broadcast/Execute, and the Gamethread then runs through that queue and processes the callbacks.
Digging a little deeper though, it looks like the HttpManager ticks on the game thread, which means finishing requests and firing the FHttpRequestCompleteDelegate on the game thread. I guess this is what you meant when you said “explicitly sending the work to the game thread” ? I took that to mean the IO transfer and was thinking “no way, that would lag the game so much” The IO transfer itself is done in a background thread managed by HttpManager
So I guess the issue I was having isn’t with the delegates themselves, but when the HttpManager decides to fire the delegates, which is on the game thread, causing my deadlock.