Taskgraph 是Unreal的一个多线程系统。基本介绍可以参考 https://wiki.unrealengine.com/Multi-Threading:_Task_Graph_System https://wiki.unrealengine.com/Multi-Threading:_How_to_Create_Threads_in_UE4
开始¶
起动是在FEngineLoop:PreInit
initialize task graph sub-system with potential multiple threads FTaskGraphInterface::Startup( FPlatformMisc::NumberOfCores?() ); FTaskGraphInterface::Get().AttachToThread?( ENamedThreads::GameThread? );
线程池¶
不同于一般的线程那就是Task的改变,直白一些那就是如何切换执行代码。一般线程在一开始create的时候,来指定函数体。 而线程池要能够动态改这个函数体,线程结构中也修改对应的代码段,也就是Runnable对象。 这个是如何实现的,线程体函数是改不了,线程自己维护一个 函数指针队列.
typedef struct {
void *(*function)(void*);
void *args;
} task;
Unreal中多线程采用的 fork/join模式。 并且也就是一个线程池的作用。
一个事务,只要设计好哪里存放数据,每一个原子操作如何操作,以及事务结束时event的Handle就行了。
FGraphEventArray 来存放event. 写一个函数的处理TasksAreComplete。 以及一个干原子操作function. 再也就是分启动初使用 function,也就是要多少thread来给你做事。但是真正由多少thread同时做,是由TaskGraph来分配的。 相当于软件开发中50个 人/月。
FGraphEventArray.Add(TgraphTask<TaskThread>::CreateTask(NULL,ENameThreads::GameThread).ConstructAndDispathWhenRead()); 从哪里开始。
然后封装一个Task Thread.
AsyncWork.h 这里很多samples. Core/Private/AsyncTaskGraph.cpp
- Questions
#. CreateTask #.
源码分析¶
- 启动在是 FEngine::PreInit 中
// initialize task graph sub-system with potential multiple threads
FTaskGraphInterface::Startup( FPlatformMisc::NumberOfCores() );
FTaskGraphInterface::Get().AttachToThread( ENamedThreads::GameThread );
#if STATS
FThreadStats::StartThread();
#endif
// Statics in FTaskGraphInterface
void FTaskGraphInterface::Startup(int32 NumThreads)
{
// TaskGraphImplementationSingleton is actually set in the constructor because find work will be called before this returns.
new FTaskGraphImplementation(NumThreads);
}
实现FTaskGraphImplementation(NumThreads);¶
- 根据CPU核数,来建立线程。
#. 最多12个线程,这个是编译的指定的, TaskGraph.cpp:2044 MAX_THREADS=12; NameThread 有四个 #. StatsThread #. RHIThread #. GameThread #. ActualRenderThread
anythread, 有3个。 并且启动这三个线程,并指定其stackSize=256*1024,最终还是调用pthread_create来创建thread. 这个可以在PThreadRunnableThread.h看到。
/**
* Wrapper for pthread_create that takes a name
*
* Allows a subclass to override this function to create a thread and give it a name, if
* the platform supports it
*
* Takes the same arguments as pthread_create
*/
virtual int CreateThreadWithName(pthread_t* HandlePtr, pthread_attr_t* AttrPtr, PthreadEntryPoint Proc, void* Arg, const ANSICHAR* /*Name*/)
{
// by default, we ignore the name since it's not in the standard pthreads
return pthread_create(HandlePtr, AttrPtr, Proc, Arg);
}
_ThreadProc 就是自己来实现 taskqueue了。
TGraphTask¶
#. 产生与处理依赖。 SetupPrereqs
调度类型¶
#. CreateAndDispatchWhenReady - Create a task and dispatch it when the prerequisites are complete #. ProcessThreadUntilRequestReturn
各种snync_syncrhonize 最终实现都是基于机器自己的,于Unreal中 MemoryBarrier 都是用指 arm “dmb ish”. http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204ic/CIHJFGFE.html