/ue-async-threading
Use this skill when working with Unreal Engine async operations, threading, parallel execution, or concurrency. Also use when the user mentions 'FRunnable', 'FAsyncTask', 'TaskGraph', 'UE::Tasks', 'ParallelFor', 'TFuture', 'TPromise', 'Async()', 'thread safety',
$ npx -y skills add quodsoler/unreal-engine-skills --skill ue-async-threading --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/ue-async-threading
Context preview
The summary Claude sees to decide when to auto-load this skill.
Use this skill when working with Unreal Engine async operations, threading, parallel execution, or concurrency. Also use when the user mentions 'FRunnable', 'FAsyncTask', 'TaskGraph', 'UE::Tasks', 'ParallelFor', 'TFuture', 'TPromise', 'Async()', 'thread safety',
SKILL.md
ue-async-threading.SKILL.mdname: ue-async-threading
description: "Use this skill when working with Unreal Engine async operations, threading, parallel execution, or concurrency. Also use when the user mentions 'FRunnable', 'FAsyncTask', 'TaskGraph', 'UE::Tasks', 'ParallelFor', 'TFuture', 'TPromise', 'Async()', 'thread safety', 'FCriticalSection', 'FRWLock', 'background thread', 'game thread dispatch', or 'thread pool'. For networking async (RPCs, replication), see ue-networking-replication. For asset streaming, see ue-data-assets-tables."
metadata:
version: 1.0.0
UE Async and Threading
You are an expert in Unreal Engine's threading model, async task systems, and concurrent programming patterns.
Context Check
Read `.agents/ue-project-context.md` before proceeding. Engine version matters: `UE::Tasks::Launch` is the modern preferred API (UE 5.0+), while `FAsyncTask` and TaskGraph remain fully supported. Determine: What work needs to be offloaded? Is UObject access required? What latency/throughput tradeoff is acceptable?
Information Gathering
Ask the user if unclear:
- **Offload type** — CPU-bound computation, I/O wait, or periodic background work?
- **UObject interaction** — Does the background work need to read/write UObject state?
- **Lifetime** — One-shot task, recurring work, or long-lived thread?
- **Result delivery** — Fire-and-forget, or does the game thread need results back?
---
UE Threading Model
UE runs several named threads plus a scalable worker pool. Understanding which thread owns what prevents the most common threading bugs.
**Named threads:**
- **Game Thread** — All UObject access, Blueprint execution, gameplay logic. Check with `IsInGameThread()`.
- **Render Thread** — Render commands, scene proxy updates. `IsInRenderingThread()`.
- **RHI Thread** — GPU command submission (platform-dependent).
- **Worker Threads** — Unnamed pool threads for task dispatch. Count scales with CPU cores.
**The golden rule:** UObjects are game-thread-only. No UPROPERTY reads, no UFUNCTION calls, no `GetWorld()`, no spawning from background threads. Violating this causes intermittent crashes that depend on GC timing and are extremely difficult to diagnose.
---
Pattern Selection Guide
Choose the simplest API that fits your needs.
| Pattern | Best For | Lifetime | Result? | |---------|----------|----------|---------| | `AsyncTask(GameThread, Lambda)` | Dispatch to game thread from background | One-shot | No | | `UE::Tasks::Launch` | General async work (preferred, UE5+) | One-shot | `TTask<T>` | | `Async(EAsyncExecution, Lambda)` | Flexible dispatch with `TFuture` | One-shot | `TFuture<T>` | | `FAsyncTask<T>` | Reusable pooled work units | Reusable | Via `GetTask()` | | `FAutoDeleteAsyncTask<T>` | Fire-and-forget pooled work | One-shot | No | | `TGraphTask<T>` | Complex dependency graphs | One-shot | `FGraphEvent` | | `ParallelFor` | Data-parallel loops | Blocking | No | | `FRunnable` + `FRunnableThread` | Long-lived dedicated threads | Persistent | Manual |
---
FRunnable and FRunnableThread
Use `FRunnable` only when you need a **dedicated, long-lived thread** -- a socket listener, a file watcher, or a continuous processing loop. For one-shot work, prefer `UE::Tasks::Launch` or `FAsyncTask`.
**Lifecycle:** `Init()` (new thread) -> `Run()` (new thread) -> `Exit()` (new thread, after Run returns). `Stop()` is called externally to request shutdown.
**FRunnableThread::Create** signature: `static FRunnableThread* Create(FRunnable*, const TCHAR* ThreadName, uint32 StackSize = 0, EThreadPriority = TPri_Normal, uint64 AffinityMask, EThreadCreateFlags)`.
**Key points:** `Stop()` signals the thread -- it does not block. `Kill(true)` calls `Stop()` then waits for completion. Always `delete` the `FRunnableThread*` after `Kill`. Use `std::atomic<bool> bShouldStop` in `Run()` loop, set it in `Stop()`.
See `references/threading-patterns.md` for a complete `FRunnable` subclass template with proper shutdown.
---
FAsyncTask and FAutoDeleteAsyncTask
For **reusable work units** on the engine thread pool (`GThreadPool`). Subclass `FNonAbandonableTask` and implement `DoWork()` + `GetStatId()`.
class FMyComputeTask : public FNonAbandonableTask
{
friend class FAsyncTask<FMyComputeTask>;
int32 Result = 0;
TArray<int32> InputData;
FMyComputeTask(TArray<int32> InData) : InputData(MoveTemp(InData)) {}
void DoWork()
{
for (int32 Val : InputData) { Result += Val; }
}
FORCEINLINE TStatId GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FMyComputeTask, STATGROUP_ThreadPoolAsyncTasks);
}
};**Usage:**
// Reusable — you manage lifetime
auto* Task = new FAsyncTask<FMyComputeTask>(MoveTemp(Data));
Task->StartBackgroundTask(); // dispatches to GThreadPool
Task->EnsureCompletion(); // blocks or runs inline if not started
int32 R = Task->GetTask().Result;
delete Task;
// Fire-and-forget — auto-deletes on completion
(new FAutoDeleteAsyncTask<FMyComputeTask>(MoveTemp(Data)))->StartBackgroundTask();
`IsWorkDone()` is the non-blocking completion check. `Cancel()` prevents execution if not yet started. `StartSynchronousTask()` runs inline on the calling thread.
---
TaskGraph
For work with **complex dependency chains**. Each task declares prerequisites; the scheduler handles ordering.
class FMyGraphTask
{
public:
FMyGraphTask(int32 InValue) : Value(InValue) {}
static ESubsequentsMode::Type GetSubsequentsMode()
{ return ESubsequentsMode::TrackSubsequents; }
ENamedThreads::Type GetDesiredThread()
{ return ENamedThreads::AnyThread; }
TStatId GetStatId() const
{ RETURN_QUICK_DECLARE_CYCLE_STAT(FMyGraphTask, STATGROUP_TaskGraphTasks); }
void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
{ /* work here */ }
private:
int32 Value;
};**Dispatching with prerequisites:**
FGraphEventArray Prerequisites;
Read more
name: ue-async-threading description: "Use this skill when working with Unreal Engine async operations, threading, parallel execution, or concurrency. Also use when the user mentions 'FRunnable', 'FAsyncTask', 'TaskGraph', 'UE::Tasks', 'ParallelFor', 'TFuture', 'TPromise', 'Async()', 'thread safety', 'FCriticalSection', 'FRWLock', 'background thread', 'game thread dispatch', or 'thread pool'. For networking async (RPCs, replication), see ue-networking-replication. For asset streaming, see ue-data-assets-tables." metadata: version: 1.0.0
UE Async and Threading
You are an expert in Unreal Engine's threading model, async task systems, and concurrent programming patterns.
Context Check
Read `.agents/ue-project-context.md` before proceeding. Engine version matters: `UE::Tasks::Launch` is the modern preferred API (UE 5.0+), while `FAsyncTask` and TaskGraph remain fully supported. Determine: What work needs to be offloaded? Is UObject access required? What latency/throughput tradeoff is acceptable?
Information Gathering
Ask the user if unclear:
- **Offload type** — CPU-bound computation, I/O wait, or periodic background work?
- **UObject interaction** — Does the background work need to read/write UObject state?
- **Lifetime** — One-shot task, recurring work, or long-lived thread?
- **Result delivery** — Fire-and-forget, or does the game thread need results back?
---
UE Threading Model
UE runs several named threads plus a scalable worker pool. Understanding which thread owns what prevents the most common threading bugs.
**Named threads:**
- **Game Thread** — All UObject access, Blueprint execution, gameplay logic. Check with `IsInGameThread()`.
- **Render Thread** — Render commands, scene proxy updates. `IsInRenderingThread()`.
- **RHI Thread** — GPU command submission (platform-dependent).
- **Worker Threads** — Unnamed pool threads for task dispatch. Count scales with CPU cores.
**The golden rule:** UObjects are game-thread-only. No UPROPERTY reads, no UFUNCTION calls, no `GetWorld()`, no spawning from background threads. Violating this causes intermittent crashes that depend on GC timing and are extremely difficult to diagnose.
---
Pattern Selection Guide
Choose the simplest API that fits your needs.
| Pattern | Best For | Lifetime | Result? | |---------|----------|----------|---------| | `AsyncTask(GameThread, Lambda)` | Dispatch to game thread from background | One-shot | No | | `UE::Tasks::Launch` | General async work (preferred, UE5+) | One-shot | `TTask<T>` | | `Async(EAsyncExecution, Lambda)` | Flexible dispatch with `TFuture` | One-shot | `TFuture<T>` | | `FAsyncTask<T>` | Reusable pooled work units | Reusable | Via `GetTask()` | | `FAutoDeleteAsyncTask<T>` | Fire-and-forget pooled work | One-shot | No | | `TGraphTask<T>` | Complex dependency graphs | One-shot | `FGraphEvent` | | `ParallelFor` | Data-parallel loops | Blocking | No | | `FRunnable` + `FRunnableThread` | Long-lived dedicated threads | Persistent | Manual |
---
FRunnable and FRunnableThread
Use `FRunnable` only when you need a **dedicated, long-lived thread** -- a socket listener, a file watcher, or a continuous processing loop. For one-shot work, prefer `UE::Tasks::Launch` or `FAsyncTask`.
**Lifecycle:** `Init()` (new thread) -> `Run()` (new thread) -> `Exit()` (new thread, after Run returns). `Stop()` is called externally to request shutdown.
**FRunnableThread::Create** signature: `static FRunnableThread* Create(FRunnable*, const TCHAR* ThreadName, uint32 StackSize = 0, EThreadPriority = TPri_Normal, uint64 AffinityMask, EThreadCreateFlags)`.
**Key points:** `Stop()` signals the thread -- it does not block. `Kill(true)` calls `Stop()` then waits for completion. Always `delete` the `FRunnableThread*` after `Kill`. Use `std::atomic<bool> bShouldStop` in `Run()` loop, set it in `Stop()`.
See `references/threading-patterns.md` for a complete `FRunnable` subclass template with proper shutdown.
---
FAsyncTask and FAutoDeleteAsyncTask
For **reusable work units** on the engine thread pool (`GThreadPool`). Subclass `FNonAbandonableTask` and implement `DoWork()` + `GetStatId()`.
class FMyComputeTask : public FNonAbandonableTask
{
friend class FAsyncTask<FMyComputeTask>;
int32 Result = 0;
TArray<int32> InputData;
FMyComputeTask(TArray<int32> InData) : InputData(MoveTemp(InData)) {}
void DoWork()
{
for (int32 Val : InputData) { Result += Val; }
}
FORCEINLINE TStatId GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FMyComputeTask, STATGROUP_ThreadPoolAsyncTasks);
}
};**Usage:**
// Reusable — you manage lifetime auto* Task = new FAsyncTask<FMyComputeTask>(MoveTemp(Data)); Task->StartBackgroundTask(); // dispatches to GThreadPool Task->EnsureCompletion(); // blocks or runs inline if not started int32 R = Task->GetTask().Result; delete Task; // Fire-and-forget — auto-deletes on completion (new FAutoDeleteAsyncTask<FMyComputeTask>(MoveTemp(Data)))->StartBackgroundTask();
`IsWorkDone()` is the non-blocking completion check. `Cancel()` prevents execution if not yet started. `StartSynchronousTask()` runs inline on the calling thread.
---
TaskGraph
For work with **complex dependency chains**. Each task declares prerequisites; the scheduler handles ordering.
class FMyGraphTask
{
public:
FMyGraphTask(int32 InValue) : Value(InValue) {}
static ESubsequentsMode::Type GetSubsequentsMode()
{ return ESubsequentsMode::TrackSubsequents; }
ENamedThreads::Type GetDesiredThread()
{ return ENamedThreads::AnyThread; }
TStatId GetStatId() const
{ RETURN_QUICK_DECLARE_CYCLE_STAT(FMyGraphTask, STATGROUP_TaskGraphTasks); }
void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
{ /* work here */ }
private:
int32 Value;
};**Dispatching with prerequisites:**
FGraphEventArray Prerequisites;
A collection of 27 AI agent skills for Unreal Engine C++ development. Built for game developers who want AI coding agents to help write correct, production-quality UE5 C++ code.
Other skills on unreal-engine-skills.
- /ue-actor-component-architecture
Use this skill when working with Actor and component design in Unreal Engine. Triggers on: Actor, component, BeginPlay, Tick, SpawnActor, lifecycle, CreateDefaultSubobject, composition, EndPlay, PostInitializeComponents, UActorComponent, USceneComponent, UINTERFACE, attachment,
Open skill - /ue-ai-navigation
Use this skill when implementing AI, AIController, behavior tree, blackboard, AI perception, NavMesh, EQS, navigation, pathfinding, State Tree, or Smart Objects in Unreal Engine. See references/behavior-tree-patterns.md for BT patterns and references/eqs-reference.md for EQS
Open skill - /ue-animation-system
Use this skill when working with Unreal Engine animation: AnimInstance, montage playback, blend space, state machine, anim notify, IK, AnimGraph, skeletal mesh, or linked anim graphs. See references/anim-notify-reference.md for notify patterns and references/locomotion-setup.md
Open skill - /ue-audio-system
Use this skill when working with audio, sound, music, UAudioComponent, PlaySoundAtLocation, SoundCue, MetaSound, attenuation, submix, concurrency, SFX, or spatial audio in Unreal Engine. See references/audio-setup-patterns.md for music system and ambient soundscape
Open skill - /ue-character-movement
Use this skill when working with character movement, CharacterMovementComponent, CMC, movement modes, walking, falling, swimming, flying, custom movement, network prediction, FSavedMove, root motion, floor detection, step-up, or character physics. Also use for 'PhysWalking',
Open skill - /ue-cpp-foundations
Use when writing Unreal Engine C++ code involving UPROPERTY, UFUNCTION, UCLASS, TArray, TMap, delegates, FString, garbage collection, or smart pointers. Also use when the user asks about "UE C++", USTRUCT, UENUM, FName, FText, TObjectPtr, TWeakObjectPtr, UObject lifetime,
Open skill

