{"id":7871,"date":"2023-04-23T08:45:19","date_gmt":"2023-04-23T06:45:19","guid":{"rendered":"https:\/\/store.algosyntax.com\/?post_type=asx-lms-tutorial-cpt&#038;p=7871"},"modified":"2026-03-09T22:19:56","modified_gmt":"2026-03-09T20:19:56","slug":"ue5-multithreading-with-ublueprintasyncactionbase","status":"publish","type":"asx-lms-tutorial-cpt","link":"https:\/\/store.algosyntax.com\/tutorials\/unreal-engine\/ue5-multithreading-with-ublueprintasyncactionbase\/","title":{"rendered":"UE5 Multithreading with UBlueprintAsyncActionBase"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"7871\" class=\"elementor elementor-7871\" data-elementor-post-type=\"asx-lms-tutorial-cpt\">\n\t\t\t\t<div class=\"elementor-element elementor-element-634c767 e-flex e-con-boxed e-con e-parent\" data-id=\"634c767\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3e9a7c1 elementor-widget elementor-widget-text-editor\" data-id=\"3e9a7c1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>Unreal Engine has multiple methods to implement Multithread and\/or latent actions. In this tutorial, we will focus on using the <a href=\"https:\/\/docs.unrealengine.com\/5.0\/en-US\/API\/Runtime\/Engine\/Kismet\/UBlueprintAsyncActionBase\/\" target=\"_blank\" rel=\"noopener\">UBlueprintAsyncActionBase<\/a>. When we use this method, Unreal Engine will automatically create blueprint nodes for our latent\/asynchronous functionality.\u00a0<\/p><p>\u00a0<\/p><p>As per the documentation, &#8220;BlueprintCallable <strong>factory functions<\/strong> for classes which inherit from UBlueprintAsyncActionBase will have a special blueprint node created for it&#8221;<br \/><br \/><\/p><p><strong>&#8220;Factory Functions&#8221;\u00a0<\/strong>means functions that can create and return an instance of our class.<br \/><br \/><\/p><p>We need to follow a few rules and steps to get this working and understand it. I&#8217;ll cover them below.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-cf44c79 e-flex e-con-boxed e-con e-parent\" data-id=\"cf44c79\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2403c72 elementor-widget elementor-widget-text-editor\" data-id=\"2403c72\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<ol><li><h2>Inherit From UBlueprintAsyncActionBase<\/h2><\/li><\/ol>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4de5d3f elementor-widget elementor-widget-text-editor\" data-id=\"4de5d3f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>First, we need to create a new class to wrap our asynchronous task. This class will contain any internal variables that we need to store and use while our task is running.<\/p><p>The class needs to inherit from <a href=\"https:\/\/docs.unrealengine.com\/5.0\/en-US\/API\/Runtime\/Engine\/Kismet\/UBlueprintAsyncActionBase\/\" target=\"_blank\" rel=\"noopener\">UBlueprintAsyncActionBase<\/a><\/p><p>It&#8217;s worth noting that you can have one or more static factory functions that can create an instance of your class, particularly if their functionality is related. For example, &#8220;Save File&#8221; and &#8220;Load File&#8221; as asynchronous functions can both be hosted under the same class, but have their own unique way of initializing the class&#8217;s variables.<\/p><p>Take a look at the UAsyncActionHandleSaveGame implementation.<\/p><p>Using a static factory function as the constructor for our class is a convenient way to initialize and store any internal variables we need while the task is executing.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-456511e elementor-widget elementor-widget-heading\" data-id=\"456511e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\">A Note On Garbage Garbage Collection<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-102109b elementor-widget elementor-widget-text-editor\" data-id=\"102109b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>An important thing to keep in mind is that the class we created is a UObject, which means that it is subject to garbage collection. As our asynchronous task is essentially related functions,\u00a0 executing within a UObject, we need to be aware that our task object will eventually be garbage collected if it doesn&#8217;t have a proper owner that is still alive.<\/p><p>\u00a0<\/p><p>To prevent this from happening prematurely, There are two ways:<\/p><p><br \/>We can manually call the &#8220;RegisterWithGameInstance()&#8221; and &#8220;SetReadyToDestroy()&#8221; functions that come with the class. Register will keep it from being garbage collected and SetReadyToDestroy() will mark it for garbage collection. I.e we are done using it.<\/p><p>\u00a0<\/p><p>Alternatively, we can use the &#8220;AddToRoot()&#8221; and &#8220;RemoveFromRoot()&#8221; functions, which allow us to control the lifetime of our task object. When are done doing our asynchronous task, we just need to &#8220;RemoveFromRoot()&#8221; and garbage collection will take care of deleting it for us.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d4e9de2 e-flex e-con-boxed e-con e-parent\" data-id=\"d4e9de2\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-778ee02 elementor-widget elementor-widget-text-editor\" data-id=\"778ee02\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<ol start=\"2\"><li><h2>Create A Blueprint Callable Factory Function\u00a0<\/h2><\/li><\/ol>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d18b4ce elementor-widget elementor-widget-text-editor\" data-id=\"d18b4ce\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>Next, we need to create a static function inside this class that is marked with the &#8220;BlueprintCallable&#8221; keyword. This function will act as a constructor for our class, allowing us to create and initialize an instance of the class from within a Blueprint graph.<\/p><p>\u00a0<\/p><p>The name we give to this function will determine what it is called within the Blueprint graph, so it&#8217;s important to choose a clear and descriptive name that accurately reflects what the function\/task does.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-63f22a5 elementor-widget elementor-widget-code-highlight\" data-id=\"63f22a5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-cpp line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-cpp\">\n\t\t\t\t\t<xmp>UCLASS()\r\nclass CUSTOM_API UCustomAsyncBase : public UBlueprintAsyncActionBase\r\n{\r\n\tGENERATED_BODY()\r\n\r\n\r\npublic:\r\n\r\n    UFUNCTION(BlueprintCallable, Category=Asyncs)\r\n\tUCustomAsyncBase* MyCustomAsynFunc()\r\n\r\n};<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-9881948 e-flex e-con-boxed e-con e-parent\" data-id=\"9881948\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-71b227d elementor-widget elementor-widget-text-editor\" data-id=\"71b227d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<ol start=\"3\"><li><h2>Set BlueprintInternalUseOnly to true<\/h2><\/li><\/ol>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-42d3a15 elementor-widget elementor-widget-text-editor\" data-id=\"42d3a15\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>When we mark our factory function as &#8220;<strong>BlueprintCallable<\/strong>&#8220;, the engine will automatically create a node for our function within the Blueprint editor.<\/p><p>However, it&#8217;s important to note that if we inherit from UBlueprintAsyncActionBase, the engine will also create a node for the factory function of that class. This means that we may end up with two nodes with the same name in the editor.<\/p><p>\u00a0<\/p><p>To avoid this, we can add the meta tag <strong>&#8220;BlueprintInternalUseOnly = true&#8221;<\/strong> to our factory function. This tells the engine that our function is intended for internal use only and should not be exposed directly in the Blueprint graph. This means that we can disable the creation of the first node triggered by &#8220;BlueprintCallable&#8221; and only leave the one triggered by the UBlueprintAsyncActionBase class.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6b535d9 elementor-widget elementor-widget-code-highlight\" data-id=\"6b535d9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-cpp line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-cpp\">\n\t\t\t\t\t<xmp>UCLASS()\r\nclass CUSTOM_API UCustomAsyncBase : public UBlueprintAsyncActionBase\r\n{\r\n\tGENERATED_BODY()\r\n\r\n\r\npublic:\r\n\r\n    UFUNCTION(BlueprintCallable, Category=Asyncs,meta=(BlueprintInternalUseOnly=\"true))\r\n\tUCustomAsyncBase* MyCustomAsynFunc()\r\n\r\n};<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4b630ea e-flex e-con-boxed e-con e-parent\" data-id=\"4b630ea\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-22613b5 elementor-widget elementor-widget-heading\" data-id=\"22613b5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">To Be Continued.... <br>\nKeep Checking for more content.<\/h2>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"featured_media":0,"template":"","asx-lms-tutorial-categories":[58,45],"asx-lms-tutorial-tags":[46],"class_list":["post-7871","asx-lms-tutorial-cpt","type-asx-lms-tutorial-cpt","status-publish","hentry","asx-lms-tutorial-categories-unreal-c-api","asx-lms-tutorial-categories-unreal-engine","asx-lms-tutorial-tags-cpp","entry"],"acf":[],"_links":{"self":[{"href":"https:\/\/store.algosyntax.com\/asx-rest\/wp\/v2\/asx-lms-tutorial-cpt\/7871","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/store.algosyntax.com\/asx-rest\/wp\/v2\/asx-lms-tutorial-cpt"}],"about":[{"href":"https:\/\/store.algosyntax.com\/asx-rest\/wp\/v2\/types\/asx-lms-tutorial-cpt"}],"version-history":[{"count":0,"href":"https:\/\/store.algosyntax.com\/asx-rest\/wp\/v2\/asx-lms-tutorial-cpt\/7871\/revisions"}],"wp:attachment":[{"href":"https:\/\/store.algosyntax.com\/asx-rest\/wp\/v2\/media?parent=7871"}],"wp:term":[{"taxonomy":"asx-lms-tutorial-categories","embeddable":true,"href":"https:\/\/store.algosyntax.com\/asx-rest\/wp\/v2\/asx-lms-tutorial-categories?post=7871"},{"taxonomy":"asx-lms-tutorial-tags","embeddable":true,"href":"https:\/\/store.algosyntax.com\/asx-rest\/wp\/v2\/asx-lms-tutorial-tags?post=7871"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}