TSync is a comprehensive multithreading library for Unreal Engine that provides Blueprint and C++ support for asynchronous task execution, thread management, and synchronization primitives.
- Blueprint Multithreading: Execute background tasks directly from Blueprints without C++ knowledge
- Raw Thread Management: Create and manage custom FRunnable threads with interface-based communication
- Mutex Support: Thread-safe synchronization with named mutexes accessible from Blueprints
- Game Thread Locks: Convenient locking mechanisms for game thread operations
- Async Task System: Predefined async task types with delegate-based completion callbacks
- Interface-Based Architecture: Clean communication between threads using UE interfaces
- Automatic Thread Cleanup: Built-in garbage collection for completed threads
- RAII Scope Locking: Automatic mutex management with scope-based unlocking
TSync consists of several key components:
AAsyncTaskManager: Main actor that manages all threading operationsUMutexWrapper: Blueprint-safe wrapper around FCriticalSectionFRawThread: Custom FRunnable implementation for background thread executionUBpAsyncNode: Blueprint async action node for background task executionUAsyncFunctionLibrary: Static utility functions for accessing the task manager
IRawThreadInterface: Interface for objects that can execute threaded operationsExecuteThreaded(): Called on background thread to perform workOnThreadFinished(): Called on game thread when work completesOnThreadExit(): Notifies thread manager of thread completion
- Unreal Engine 4.25+ or Unreal Engine 5.x
- Visual Studio 2019+ (Windows) or Xcode (macOS) or GCC/Clang (Linux)
- C++17 compatible compiler
-
Plugin Installation:
# Copy TSync folder to your project's Plugins directory cp -r TSync /path/to/YourProject/Plugins/ -
Enable in Project:
- Open your Unreal Engine project
- Go to Edit → Plugins
- Find "TSync" under "Other" category
- Enable the plugin
- Restart the editor when prompted
-
Add Module Dependency (for C++ projects):
// In YourProject.Build.cs PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "TSync" // Add this line });
# Generate project files
./GenerateProjectFiles.sh # Linux/Mac
# or
GenerateProjectFiles.bat # Windows
# Build the project
# This will automatically build TSync as a dependency-
Place AsyncTaskManager in Level:
- Drag
AsyncTaskManageractor into your level - Or spawn it dynamically in Blueprint
- Drag
-
Get Task Manager Reference:
// In Blueprint: Call "Get Async Task Manager" function -
Execute Async Task:
// In Blueprint: // 1. Call "Execute Task" on AsyncTaskManager // 2. Set Task Type (enum) // 3. Set Requester (self reference) // 4. Bind to "On Task Complete" delegate
// In Blueprint:
// 1. Right-click → Add Node → "Run Background Task"
// 2. Connect execution to "Task" output pin (runs on background thread)
// 3. Connect completion logic to "Game Thread Task" output pin (runs on game thread)// Lock a mutex
AsyncTaskManager → Lock("MyMutexName")
// Unlock a mutex
AsyncTaskManager → Unlock("MyMutexName")
// Scope lock (automatically unlocks when object is destroyed)
ScopedMutex = AsyncTaskManager → Scope Lock()
// Game thread locks (for simple game thread synchronization)
AsyncTaskManager → Game Thread Lock("MyLock")
AsyncTaskManager → Game Thread Unlock("MyLock")
bool IsLocked = AsyncTaskManager → Is Game Thread Locked("MyLock")// In Blueprint:
// AsyncTaskManager → Start Raw Thread
// - Thread Name: "MyWorkerThread"
// - Target: Object implementing IRawThreadInterface
// - Reference Object: Optional data object
// - Command: String command for the target
// - Options: Array of string parameters
// - Auto Stop Thread: true (automatically cleanup when done)// MyThreadWorker.h
UCLASS()
class MYGAME_API UMyThreadWorker : public UObject, public IRawThreadInterface
{
GENERATED_BODY()
public:
// Implement the interface
virtual void ExecuteThreaded_Implementation(UObject* ReferenceObject,
const FString& Command, const TArray<FString>& Options) override;
virtual void OnThreadFinished_Implementation(UObject* ReferenceObject,
const FString& Command, const TArray<FString>& Params) override;
};
// MyThreadWorker.cpp
void UMyThreadWorker::ExecuteThreaded_Implementation(UObject* ReferenceObject,
const FString& Command, const TArray<FString>& Options)
{
// This runs on background thread
// Perform heavy computation here
// When done, call OnThreadFinished on game thread
AsyncTask(ENamedThreads::GameThread, [this, ReferenceObject, Command]()
{
TArray<FString> Results = {"Result1", "Result2"};
OnThreadFinished_Implementation(ReferenceObject, Command, Results);
});
}
void UMyThreadWorker::OnThreadFinished_Implementation(UObject* ReferenceObject,
const FString& Command, const TArray<FString>& Params)
{
// This runs on game thread
// Update UI, game state, etc.
}// Get the task manager
AAsyncTaskManager* TaskManager = UAsyncFunctionLibrary::GetAsyncTaskManager();
// Create worker object
UMyThreadWorker* Worker = NewObject<UMyThreadWorker>();
// Start thread
TaskManager->StartRawThread(
TEXT("MyWorkerThread"),
Worker, // Target object
nullptr, // Reference object (optional)
TEXT("ProcessData"), // Command
{TEXT("Param1"), TEXT("Param2")}, // Options
true // Auto stop
);// Get task manager
AAsyncTaskManager* TaskManager = UAsyncFunctionLibrary::GetAsyncTaskManager();
// Lock/unlock manually
TaskManager->Lock(TEXT("MyMutex"));
// ... critical section code ...
TaskManager->Unlock(TEXT("MyMutex"));
// Scope lock (RAII)
UMutexWrapper* ScopedLock = TaskManager->ScopeLock();
// Automatically unlocks when ScopedLock goes out of scope| Function | Description |
|---|---|
ExecuteTask(EAsyncTaskBp, UObject*) |
Execute predefined async task |
StartRawThread(...) |
Create custom background thread |
Lock(FString) |
Lock named mutex |
Unlock(FString) |
Unlock named mutex |
ScopeLock() |
Create RAII scoped mutex |
GameThreadLock(FString) |
Simple game thread lock |
GameThreadUnlock(FString) |
Unlock game thread lock |
IsGameThreadLocked(FString) |
Check if game thread lock is active |
SetThreadPriority(int32) |
Set default thread priority |
KillThread(FString) |
Manually terminate thread |
| Priority | Value | Description |
|---|---|---|
| Any Background Task | 0 | Low priority background work |
| Any High Priority Task | 1 | High priority background work |
| Any Background Thread | 2 | Background thread pool |
| Any High Priority Thread | 3 | High priority thread pool |
// Blueprint: Process large file in background
// 1. Get AsyncTaskManager reference
// 2. Call StartRawThread with FileProcessor target
// 3. FileProcessor reads file on background thread
// 4. Results returned via OnThreadFinished callback
// 5. Update UI on game thread// C++: Async HTTP request
class UHttpWorker : public UObject, public IRawThreadInterface
{
virtual void ExecuteThreaded_Implementation(UObject* ReferenceObject,
const FString& Command, const TArray<FString>& Options) override
{
// Perform HTTP request on background thread
FString Response = MakeHttpRequest(Options[0]);
// Return to game thread
AsyncTask(ENamedThreads::GameThread, [this, Response]()
{
OnThreadFinished_Implementation(nullptr, TEXT("HttpComplete"), {Response});
});
}
};