There are multiple places in project where UE function IsInGameThread() is used to validate if the task is running on a game thread. In some cases ensure (subj) is triggered when function is called. From code (./Runtime/Core/Private/HAL/ThreadingBase.cpp) I can see the condition validated (FTaskTagScope::IsCurrentTag(ETaskTag::EGameThread) || FTaskTagScope::IsRunningDuringStaticInit() is expected to be ‘true’ on a game thread. What could be a reason for this ensure? For what reason for example FTaskTagScope::IsCurrentTag(ETaskTag::EGameThread) could return false/0 when called on a game thread? There are suspicion that ensure failure could be caused by iOS (objective-C) and/or android native code (plugin implementation) like ‘dispatch_async(dispatch_get_main_queue(), ^{})’ or call to runOnUiThread (on android). But these are just assumptions. It’s important to understand for what real reason ensure fails and how to solve issue like this.
Steps to Reproduce
This ensure is triggered after call to IsInGameThread() on a project code. This is not a bug on a UE side, but we need to understand for what reason this ensure is triggered on custom UE project after call to IsInGameThread()
Hi,
could you provide some example callstacks (potentially removing your game specific names if sensitive) from when you’ve hit those asserts?
Ideally also with an example of how you’re scheduling your code that should run on the gamethread, i.e. with async tasks or something else.
There have been a few cases where tasks could be run in unexpected places (e.g. during input handling or during a slow task in Editor ), so the call stack should give us more detail on whether those interactions are supposed to happen. If it’s an edge case we missed it might be necessary to correctly tag those scopes/call stacks as game thread.
Kind Regards,
Sebastian
I’m sorry for delay.. Right now we don’t know exact location in code where this ensure is triggered - at a moment we have only logs from sentry and looks like there are multiple places in code where this ensure is triggered. For now it’s important to understand what this ensure actually means. For example condition like FTaskTagScope::IsCurrentTag(ETaskTag::EGameThread) - looks like in some cases it returns ‘false’ when task is executed on game thread. Right now it’s not clear where ‘current tag’ is set and should this tag be set manually when we run code on game thread (for example when calling AsyncTask(ENamedThreads::GameThread, …)
Hi Edvinas,
The oldValue != newValue assert is generally because the technique that was used before to determine if we were on the game thread (thread ID) doesn’t match with the new TaskTagScope thread_local value.
What is expected is that there is FTaskTagScope setting the current thread as the game thread in your Main() function of the application. This should be very early and possibly the very first call that needs to happen after entering main. This is generally done by UE for most platforms that already have a Main entry point. For custom applications like BlankProgram and other command-let, we generally have to set it manually.
BlankProgram.cpp contains this, for example.
INT32_MAIN_INT32_ARGC_TCHAR_ARGV()
{
FTaskTagScope Scope(ETaskTag::EGameThread);
...
}
The is the most likely cause why the ensure would be firing. But it’s also possible that some platform specific code is at play.
Before that happens, the default value is EStaticInit, and both are considered the game-thread.
Once the main thread is setup properly, you should never set those tags manually unless you need to go wide inside a ParallelFor and you expect some checks to validate things are only done in game-thread or parallel-game-thread where the GT is guaranteed to be stopped. In case that’s what is needed… you will see a few ParallelFor in the engine doing something like this inside the ParallelFor lamba.
FTaskTagScope Scope(ETaskTag::EParallelGameThread);
// The following code will be marked as running in parallel while the GT is blocked
Hope this helps,
Danny