您的位置:首页 > 其它

虚幻4 Task小记

2016-04-09 16:08 295 查看
TGraphTask类里面有一个FConstructor类,用来创建TGraphTask。

FGraphEventRef ConstructAndDispatchWhenReady(T&&... Args)
{
new ((void *)&Owner->TaskStorage) TTask(Forward<T>(Args)...);
return Owner->Setup(Prerequisites, CurrentThreadIfKnown);
}


这个就直接字面意思,创建一个TGraphTask,但是等他的prerequisites都触发了,才把这个任务分发。也就是进入队列。

FConstructor(TGraphTask* InOwner, const FGraphEventArray* InPrerequisites, ENamedThreads::Type InCurrentThreadIfKnown)
: Owner(InOwner)
, Prerequisites(InPrerequisites)
, CurrentThreadIfKnown(InCurrentThreadIfKnown)
{
}


创建的时候可以传入一个EVENT数组,这个Constructor创建TGraphTask时候回判断需求的event是否都已经触发了,如果没有触发,那就先不创建。

void SetupPrereqs(const FGraphEventArray* Prerequisites, ENamedThreads::Type CurrentThreadIfKnown, bool bUnlock)
{
checkThreadGraph(!TaskConstructed);
TaskConstructed = true;
TTask& Task = *(TTask*)&TaskStorage;
SetThreadToExecuteOn(Task.GetDesiredThread());
int32 AlreadyCompletedPrerequisites = 0;
if (Prerequisites)
{
for (int32 Index = 0; Index < Prerequisites->Num(); Index++)
{
check((*Prerequisites)[Index]);
if (!(*Prerequisites)[Index]->AddSubsequent(this))
{
AlreadyCompletedPrerequisites++;
}
}
}
PrerequisitesComplete(CurrentThreadIfKnown, AlreadyCompletedPrerequisites, bUnlock);
}


PrerequisitesComplete

函数就是判断是否所有event都触发过的函数。

TGraphTask里面有一个变量

/** A reference counted pointer to the completion event which lists the tasks that have me as a prerequisite. **/
FGraphEventRef				Subsequents;


当这个任务执行完时候,会触发这个event,这个event保存了对于他有依赖的所有FConstructor,是一个数组,

然后会告诉constructor,这个event触发了,看看是不是可以执行了。

然后一堆constructor有的发现确实所需要的event都触发了,就创建一个task,有的发现还有没有触发的event,就不创建,继续等待。

这个就是event触发时候调用的函数。

/**
*	"Complete" the event. This grabs the list of subsequents and atomically closes it. Then for each subsequent it reduces the number of prerequisites outstanding and if that drops to zero, the task is queued.
*	@param CurrentThreadIfKnown if the current thread is known, provide it here. Otherwise it will be determined via TLS if any task ends up being queued.
**/
CORE_API void DispatchSubsequents(TArray<FBaseGraphTask*>& NewTasks, ENamedThreads::Type CurrentThreadIfKnown = ENamedThreads::AnyThread);


void FGraphEvent::DispatchSubsequents(TArray<FBaseGraphTask*>& NewTasks, ENamedThreads::Type CurrentThreadIfKnown)
{
if (EventsToWaitFor.Num())
{
// need to save this first and empty the actual tail of the task might be recycled faster than it is cleared.
FGraphEventArray TempEventsToWaitFor;
Exchange(EventsToWaitFor, TempEventsToWaitFor);
// create the Gather...this uses a special version of private CreateTask that "assumes" the subsequent list (which other threads might still be adding too).
DECLARE_CYCLE_STAT(TEXT("FNullGraphTask.DontCompleteUntil"),
STAT_FNullGraphTask_DontCompleteUntil,
STATGROUP_TaskGraphTasks);

TGraphTask<FNullGraphTask>::CreateTask(FGraphEventRef(this), &TempEventsToWaitFor, CurrentThreadIfKnown).ConstructAndDispatchWhenReady(GET_STATID(STAT_FNullGraphTask_DontCompleteUntil), ENamedThreads::HiPri(ENamedThreads::AnyThread));
return;
}

#if USE_NEW_LOCK_FREE_LISTS
bComplete = true;
int32 SpinCount = 0;
while (true)
{
FBaseGraphTask* NewTask = SubsequentList.Pop();
if (!NewTask)
{
if (SubsequentList.CloseIfEmpty())
{
break;
}
LockFreeCriticalSpin(SpinCount);
continue;
}
NewTask->ConditionalQueueTask(CurrentThreadIfKnown);
}
#else
SubsequentList.PopAllAndClose(NewTasks);
for (int32 Index = NewTasks.Num() - 1; Index >= 0 ; Index--) // reverse the order since PopAll is implicitly backwards
{
FBaseGraphTask* NewTask = NewTasks[Index];
checkThreadGraph(NewTask);
NewTask->ConditionalQueueTask(CurrentThreadIfKnown);
}
NewTasks.Reset();
#endif
}


NewTask->ConditionalQueueTask(CurrentThreadIfKnown);


能看到最后这个函数,就是让Task判断是否要进入队列了。

<pre name="code" class="cpp">	/**
*	An indication that a prerequisite has been completed. Reduces the number of prerequisites by one and if no prerequisites are outstanding, it queues the task for execution.
*	@param CurrentThread; provides the index of the thread we are running on. This is handy for submitting new taks. Can be ENamedThreads::AnyThread if the current thread is unknown.
**/
void ConditionalQueueTask(ENamedThreads::Type CurrentThread)
{
if (NumberOfPrerequistitesOutstanding.Decrement()==0)
{
QueueTask(CurrentThread);
}
}



就是让TGraphTask自己看看是不是可以执行了。

PrerequisitesComplete

/** An aligned bit of storage to hold the embedded task **/
TAlignedBytes<sizeof(TTask),ALIGNOF(TTask)> TaskStorage;


CreateTask
其实就是创建了一个Task,但是没有和我们自己宏创建的那个类有关联,就是创建了一个空壳。
ConstructAndDispatchWhenReady
才是吧自己宏创建的那个类实例化,放在TGraphTask的一个变量里面。
当执行这个task时候,执行自己的那个类的DoTask()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: