2020-08-17_13:41:16
Look at ObjectTools::DeleteObjects
.
Uses FAssetDeleteModel
, DeleteModel->Tick
, DeleteModel->GetState
, DeleteModel::GetProgress
, and GWawn->StatusUpdate
.
Somewhat reduced:
TSharedRef<FAssetDeleteModel> DeleteModel = MakeShareable(
new FAssetDeleteModel(ObjectsToDelete));
bool bUserCanceled = false;
GWarn->BeginSlowTask(
NSLOCTEXT("UnrealEd", "VerifyingDelete", "Verifying Delete"),
true, true);
while (!bUserCanceled &&
DeleteModel->GetState() != FAssetDeleteModel::Finished)
{
DeleteModel->Tick(0);
GWarn->StatusUpdate(
(int32)(DeleteModel->GetProgress() * 100),
100, DeleteModel->GetProgressText());
bUserCanceled = GWarn->ReceivedUserCancel();
}
GWarn->EndSlowTask();
Example of how to setup a background task using FRunnable
.
This example may be incomplete, more reading necessary.
It seems to create a new thread for each execution. How do I use a thread pool instead?
class AMyActor : public AActor
{
public:
void BeginPlay();
private:
void CheckIsWorkerDone();
private:
// What should the pointer type be? Should it be marked UPROPERTY?
FMyWorker* MyWorker;
FTimerHandle WorkerTimerHandle;
}
void AMyActor::BeginPlay()
{
MyWorker = FMyWorker::Launch();
if (!GetWorldTimerManager().IsTimerActive(WorkerTimerHandle))
{
GetWorldTimerManager().SetTimer(
WorkerTimerHandle, this, &AMyActor::CheckIsWorkerDone, 0.5f, true);
}
}
FMyWorker* FMyWorker::Launch()
{
if (!FPlatformProcess::SupportsMultithreading())
{
return nullptr;
}
if (Runnable != nullptr)
{
return Runnable;
}
Runnable = new FMyWorker();
return Runnable;
}
class FMyWorker : public FRunnable /* I think, or a subclass of FRunnable. */
{
public:
static FMyWorker* Launch();
virtual uint32 Run() override; /* The API reference says that Run isn't virtual. Odd. */
virtual void Stop() override;
private:
static FMyWorker* Runnable;
// What should the pointer type be? Should it be marked UPROPERTY?
FRunnableThread* Thread;
}
FMyWorker::FMyWorker()
{
Thread = FRunnableThread::Create(this, TEXT("FMyWorker"), 0, TPri_BelowNormal);
}
uint32 FMyWorker::Run()
{
/* Put your background code here. */
}
TFuture<void> future = Async(EAsyncExecution::ThreadPool, [/*captures*/]() {
// Do the background work here.
// Not safe to do GameThread-only stuff here, such as SetActorLocation.
// Schedule an "apply" task to apply the result of the background work onto any U-objects.
AsyncTask(ENamedThreads::GameThread, [/*captures*/]() {
// This is run on the game thread, so safe to do SetActorLocation and such.
});
});
void Example()
{
// Create an Async Task defined in MyAsyncTask
FAsyncTask<ExampleAsyncTask>* MyTask = new FAsyncTask<MyAsyncTask>(5);
// Do either...
// Start in a background thread:
MyTask->StartBackgroundTask();
// ...or...
// Run in this thread
MyTask->StartSynchronousTask();
// Check if the task is done:
if (MyTask->IsDone())
{
}
// Spinning on IsDone is not acceptable (see EnsureCompletion), but it is ok to check once a frame.
// Ensure the task is done, doing the task on the current thread if it has not been started, waiting until completion in all cases.
MyTask->EnsureCompletion();
// We're done, delete the task.
delete Task;
}
This is an example of a background task that does some work on a set of Actors when asked to. The asking is done by signaling a Start Event.
Header:
class MYMODULE_API FMyRunnable final : public FRunnable
{
private:
bool bKeepRunning = true;
FRunnableThread* Thread = nullptr;
public:
FEvent* StartEvent = nullptr;
TArray<TWeakObjectPtr<AMyActor>> MyActors;
FMyRunnable(const TArray<TWeakObjectPtr<AMyActor>>& InMyActors)
: MyActors(InMyActors)
{
StartEvent = FGenericPlatformProcess::GetSynchEventFromPool(false);
Thread = FRunnableThread::Create(this, TEXT("yRunnable"), 0, TPri_Normal);
}
};
Implementation:
uint32 FMyRunnable::Run()
{
// This explicit pinning stuff might not be necessary, pin while operating
// on a particular instance instead. Not sure what's better.
TArray<TSharedObjectPtr<AMyActor>> PinnedActors;
PinnedActors.Reserve(MyActors.Num());
for (TWeakPtr<AArmyManagerNEW> MyActor : MyActors)
{
PinnedActors.Add(MyActor.Pin());
}
while (bKeepRunning)
{
StartEvent->Wait();
for (TSharedObjectPtr<AMyActor> MyActor : PinnedActors)
{
// Do something with MyActor.
}
}
return 0;
}
[[2021-04-28_13:14:13]] Editor progress bar
Unreal 4 Threading - Running a Task on a Worker Thread @ YouTube