AsyncTask Function

There is a simple way of executing code in a seperate thread as well as pass in parameters without any workers or runnable tasks.

Updated almost 4 years ago

AsyncTask's cannot be canceled, once it runs, it runs until the action is complete!

What is it?

If you require a quick way of just handling some demanding code on a thread without creating a whole worker class or some weird extra macros then the AsyncTask Function is what your looking for! Lets look how we can implement it.

Example Video

The basic structure looks pretty much like this:

// Schedule a task on any thread with a high or normal priority
AsyncTask(ENamedThreads::AnyHiPriThreadNormalTask, [Params ...] ()
{
        
     // Do some stuff here... 
        
	// Once the task is done schedule a task back to the gamethread.
    // This is optional depending on the situation, you don't have to go back to the mainthread. 
	AsyncTask(ENamedThreads::GameThread, [Params ...] ()
	{
              // Return something or execute a delegate 
	});
});

AsyncTask can also be used for pretty much anything in C++, just make sure that incase you want to edit say an actors values asynchronously that you pass in a TWeakObjectPtr of that object in order to do so.

Implementing AsyncTask in a static BP Function

Lets implement it in a classic scenario of counting prime numbers, we're going to use a BlueprintFunctionLibrary and implement a static function that then counts the prime numbers and executes a delegate every 1000th find.

//HEADER
#pragma once

// Core includes
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"

// generated.h
#include "BPFunctionTest.generated.h"

// Our delegate to return our value
DECLARE_DYNAMIC_DELEGATE_OneParam(FTestDelegate, FString, StringOut);

UCLASS()
class PLUGINFACTORY_API UBPFunctionTest : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()
	
	/** Executes every 1000th Prime count */
	UFUNCTION(BlueprintCallable, Category = "AsyncTest", meta=(DisplayName="AsyncTest", Keywords = "async"))
        static void AsyncPrimeCount(FTestDelegate Out, int32 PrimeCount);
	
};

Most of the code here is not important, the only parts that are important are the AsyncTask functions, the delegate and when we execute each. In short its really straight forward.

//CPP
#include "BPFunctionTest.h"

void UBPFunctionTest::AsyncPrimeCount(FTestDelegate Out, int32 PrimeCount)
{
    // Schedule a thread                               // Pass in our parameters to the lambda expression
    AsyncTask(ENamedThreads::AnyHiPriThreadNormalTask, [Out, PrimeCount] ()
    {
        // This whole code just loops through numbers and counts how many prime nums it finds
        int PrimesFound = 0;
        int TestNumber = 2;

        while (PrimesFound < PrimeCount)
        {
            bool bIsPrime = true;

            for (int i = 2; i < TestNumber / 2; i++)
            {
                if (TestNumber % i == 0)
                {
                    bIsPrime = false;
                    break;
                }
            }

            if (bIsPrime)
            {
                PrimesFound++;

                // Every 1000 prime...
                if(PrimesFound % 1000 == 0)
                {
                    // We schedule back to the main thread and pass in our params
                    AsyncTask(ENamedThreads::GameThread, [Out, PrimesFound] ()
                    {
                        // We execute the delegate along with the param
                        Out.ExecuteIfBound(FString::FromInt(PrimesFound)); 
                    });
                }
            }
            TestNumber++;
        }
    });
}