利用无锁多线程实现游戏资源的加载

    技术2025-01-08  65

    www.joy70.com

     

    出于资源加载效率方面的考虑,我们使用无锁多线程来实现这一模块。

     

    类型设计:

    1.       任务信息:

    struct TaskInfo

    {

           T task;                //任务标识

           TaskType  taskType;    //任务类型, LOAD/FREE/NONE(主线程可写,子线程只读)

           TaskState  taskState;   //任务当前状态, NA/TODO/DONE(主线程可写,子线程只读)

           unsigned int  uiPriority; //任务优先级,(主线程可写,子线程只读)

           unsigned int  uiPushbackTimes; //任务被搁置的次数,(主线程可写,子线程只读)

           void* handle;          //资源地址,(主线程只读,子线程可写)

           unsigned long ulSize;    //资源长度,(主线程只读,子线程可写)

    };

    2.       任务队列:

    class TaskQueue

    {

            //仅供主线程访问

            //TaskQueue中,为所资源建立索引

            void Initialize(); 

     

            //仅供主线程访问

            //TaskQueue中任务数不变,仅仅将资源对应的任务类型改为LOAD/FREE,任务状态//改为TODO

            void AddTask(); 

     

            //仅供主线程访问

            //仅将资源对应的任务类型改为NONE

            void RemoveTask(); 

     

            //仅供子线程访问

            //从任务队列中找到最需要执行的一个任务,由任务调度算法决定

            TaskInfo GetTask();

     

            //仅供子线程访问

            //任务完成后,将资源地址传给任务的handle,大小传给任务的ulSize

            void TaskDone();

    };

     

    加载流程:

    1.       初始化任务队列TaskQueue,为每个资源定义一个TaskInfo 对象加入队列,置初始状态。

    2.       当有资源需要加载/释放时,主线程调用AddTask()改变该资源对应的TaskInfo的状态

    3.       子线程循环调用GetTask(),从TaskQueue中取得要执行的任务,若有,则执行之。

    4.       子线程执行完任务,调用TaskDone()将资源地址和长度保存;若为释放任务,则将资源地址置NULL,长度置0.

     

    说明:

    1.       任务队列长度固定,所以避免了插入/删除造成的主/子线程信息的不一致。

    2.       对于同一变量,主线程和子线程只有一方具有可写权,从而避免信息冲突。

    3.       主线程和子线程,一方读,另一方写,这种情况下,信息的不一致可通过程序逻辑加以避免。

     

     

    本文代码片段均为伪代码,不可直接使用。

    由于作者水平有限,不足之处,还望大家批评指正!

    最新回复(0)