GameFrameWork框架学习——Base——TaskPool

发布时间:2026/10/30 4:56:24
GameFrameWork框架学习——Base——TaskPool

在看Resources模块之前,因为它依赖TaskPool,所以先看一下TaskPool模块。

TaskStatus


任务的执行状态,未开始,进行中,执行结束。
继承了byte,可以将当前结构体对象进行位运算。

TaskInfo

这是一个任务信息类,用来查看当前Task的执行状态,因为用来查看所以用struct。

m_IsValid:任务是否有效。
m_SerialId:任务的序列编号,也就是Task对应的ID。
m_Tag:任务的标签。
m_Priority:任务的优先级。
m_UserData:任务的自定义数据。
m_Status:任务的执行状态。
m_Description:任务描述的文本。

之后就是围绕这些参数的属性。

StartTaskStatus


开始处理任务的标志,比如执行一个Task时候,瞬间完成了(或者说同步完成了),那么获取StartTaskStatus就是Done,如果这个Task被排队了,那么获得的就是HasToWait。

TaskBase


首先它是一个作为Task任务的抽象基类,继承IReference也就是被引用池管理着。
DefaultPriority是一个默认的优先级数,用来给新创建的TaskBase子类对象赋值。
m_SerialId是当前TaskBase的唯一序列码。
m_Tag是当前Task的标签Tag,有时候可以根据Task的标签来拿拥有同一个tag的任务。
m_Priority是Task的优先级,添加一个任务时,会将优先级高的排在前面执行。
m_UserData是获取任务的用户自定义数据。

这些是对应的属性。

然后Description是设置的任务描述。
Initialize是初始化TaskBase任务,传入序列号,标签,优先级,用户自定义数据。
Clear是将使用的信息都设置为默认或者清空。

ITaskAgent


它是负责处理一个TaskBase的子类任务的,内部维护一个Task属性,类型是继承了TaskBase的。
内部Initialize用来初始化代理。
Update用来通过任务代理执行任务。
ShutDown关闭代理。
Start开始用代理跑任务TaskBase。返回的内容是跑这个任务的结果,是直接结束,还是排队等待。
Reset停止正在处理的TaskBase任务并且重置任务。

TaskPool

任务池模块,用于加入新任务TaskBase,通过Agent任务代理来执行任务。

首先要求引用池里的任务类型必须是继承了TaskBase的。
m_FreeAgents用栈存储所有没有在运行的代理。
m_WorkingAgents用GF框架内的链表存储所有正在运行的代理,而且因为是链表,它是有序并且知道下一个上一个和头尾的。
m_WaitingTasks用GF框架的链表存储了所有正在等待执行的继承了BaseTask的任务,它们在添加新的任务时候会根据优先级排序,由大到小。
m_Paused是否TaskPool被暂停。

属性,包括是否暂停,获取Agent总数量,获取未在执行的Agent的总数量,获取工作中的Agent的数量,获取等待中的任务的数量。

Update是任务池轮询执行,只要没有暂停,就执行ProcessRunningTasks处理运行中的Task和ProcessWaitingTasks处理等待中的Task。
Shutdown是关闭任务池,先将所有任务移除,之后如果未在使用的Agent大于0就执行弹出并且关闭这个Agent。

处理正在运行的任务Task。
先拿到正在工作的Agent的第一个节点,然后进入循环,先取到这个节点的Task,如果取到的节点的Task没有结束,那么就执行这个Agent的Update,然后将当前节点设置为下一个节点,然后结束本次循环,直到出现从节点里取到的task的Done为true也就是完成了,那么取出当前节点的下一个节点留着,然后把当前节点的Agent执行Reset,并且压入非正在执行的Agent的链表中,然后从正在工作的Agent的链表中移除,然后通过引用池回收内部的task,最后将刚刚取出的"下一个节点"设置为当前节点。

所以它做了什么?遍历所有节点,如果当前遍历的节点没结束,就执行对应节点内的Agent的Update,然后遍历下一个节点;如果结束了,就把当前这个节点Agent复位,然后压进FreeAgent,从WorkingAgents拉出,然后让引用池回收,最后让当前节点的下一个节点替换自己完成遍历更迭。

处理等待中的Tasks。
将等待中的Tasks链表节点取出来第一个,从头开始循环,只要取出来这个不为空并且剩余空闲Agent的个数大于0,那么就能继续循环,只要没有空闲Agent或者current遍历完了,就退出循环。
先从空闲Agent里取出一个,加到工作中Agent最后.
然后取出等待中Task的第一个的current的值(也就是存储的task)。
然后把current的下一个等待中Task节点取出来给到next,之后用。
执行刚刚加入到工作中agent的开始,传入task,得到运行后的状态。
如果状态是完成,或者排队,或者未知错误,说明这个agent的工作结束了,就把agent重置,压回空闲Agent栈,先后从工作中的Agent里移除掉。
再判断如果状态是完成,或者可以继续处理此任务,或者未知错误,那么就把current当前这个Task从等待Task链表中移除。
再判断状态如果是完成,或者状态是未知错误,就通过引用池将task对象回收。
然后使current等于刚刚存储的current.next,遍历下一个等待中Tasks链表的节点。
HasToWait 之后 current 依然前进到 next——这避免了死循环。

所以它做了什么,先从 m_WaitingTasks 取一个节点,从这个节点开始遍历。
然后如果能取到这个节点并且有空闲Agent才能遍历,否则无法通过agent安排任务。
然后从空闲agent里弹出一个,加到工作agents里,之后取到当前遍历的task,这个时候存一下下一个task的引用,通过刚刚获得的这个工作agent来start取出的task。
此时通过agent执行task后,如果返回结果是Done或者UnKnownError,说明直接就把task执行完了,那么就把agent给重置了,把刚刚使用的agent还给空闲agents,并且将这个agent从工作中agent移除,然后把这个task从等待中task移除,然后把task通过引用池给释放了。
如果返回是HasToWait,那么把agent给重置了,把刚刚使用的agent还给空闲agents,并且将这个agent从工作中agent移除,task不动,还在等待链表里。
如果返回的是CanResume,那么agent不动,只把task从等待的tasks链表里移除,之后agent内还有这个task可以继续处理,直到返回为其他内容。


然后是ShutDown里调用的移除所有任务。
先得到等待中的任务和工作中agent的数量,从而得到所有task的数量。
遍历等待中的task,直接通过引用池回收,然后清空链表。
如果是工作中的task,那遍历工作中agent,先把当前遍历的工作中agent的task取出来,然后将agent重置并且压到空闲agent里,再通过引用尺将task回收。
最后清理工作中agent。
然后返回清理的task的数量。

添加Agent,传递参数为继承了ITaskAgent的具体代理对象。
执行这个agent的初始化,然后把它放入空闲agent里。

根据任务的编号来获取具体的任务信息。
先遍历工作中的Agents,取出遍历的那个agent的Task,判断一下ID是否相同,相同就把信息放到一个TaskInfo对象内并返回。
如果工作中Agent里没有,那么就从等待中task链表循环,如果有ID一样的,就将task的信息组成一个TaskInfo并返回。
如果都没有找到,返回一个默认的TaskInfo。

根据tag获取任务信息,返回数组或者List。
内部通过遍历工作中Agents,判断agent的task的tag和需要的一样,就把信息创建一个TaskInfo对象内并加到返回数组里;然后遍历等待中的Task链表,如果tag一样就也创建TaskInfo对象加到返回数组里。

这两个都是获取所有Task的信息,遍历工作中Agents和等待中Task,然后根据它们的Task的信息构成一个TaskInfo对象加到返回数组里。

添加任务和移除任务。
添加任务:
参数类型必须继承TaskBase,然后从等待中Task取最后一个节点,然后通过while遍历,如果有节点内的task的优先级比传入的task的优先级高,那么就停止循环,将新添加的task放在这个节点的后面;如果没有新加的task的优先级大的,就把current设置为current的前一个,直到遍历current为空结束退出循环,此时将新节点加在最前面。
移除任务:
传入任务序列号ID,遍历等待中tasks内的task的序列号id是否和需要的一样,如果一样,就把这个task从等待tasks中移除,然后通过引用池回收,之后返回true;如果前面的没有返回,那么说明等待中tasks链表里没有找到,就从工作中agent里找。
从工作中agent的头部拿,只要遍历的不为空就持续遍历;判断agent内的task的序列编号是否是需要的,如果是,就先将当前工作中的agent重置,然后压入空闲agent里,再从工作agents里移除掉,之后通过引用池回收这个task,返回true。
如果返回完了都没有,就返回false,说明没找到这个id的task。


根据tag移除任务。
先从等待中Task链表拿第一个节点,然后从头遍历,取到每一个节点里的task并且判断tag是否与需要的相等,如果相等,就把这个task从等待tasks链表里移除,然后通过引用池回收;之后计数增加。
之后从工作中agent的头部开始遍历,取到当前工作中的agent,从agent里取到task。
如果task的tag与需要的匹配,那么将当前agent执行reset复位,然后压到空闲agents里,并且从工作中agents里移除,然后通过引用池回收这个task。之后计数增加。
最后返回回收的相同的tag的task的数量。

OK,TaskPool模块结束了,因为是internal所以无法直接测试,后续看Resources模块的时候会用到,之后直接看实现好的Agent和BaseTask子类。