• 从零开始のcocos2dx生活(三)Scheduler


    取模

    对-1取模是现将-1加上除数的整数倍大于零后再取模。

    Timer()

    变量

    		float _elapsed;              // 渡过的时间.
        bool _runForever;            // 状态变量,标记是否永远的运行。
        bool _useDelay;              // 状态变量,标记是否使用延迟
        unsigned int _timesExecuted; // 记录已经执行了多少次。
        unsigned int _repeat;        // 定义要执行的总次数,0为1次  1为2次 ……
        float _delay;                // 延迟多少秒,是指在触发之前的延迟,在触发之后叫间隔,使用interval设置
        float _interval;             // 时间间隔。
    
     _scheduler(nullptr)
    , _elapsed(-1)
    , _runForever(false)
    , _useDelay(false)
    , _timesExecuted(0)
    , _repeat(0)
    , _delay(0.0f)
    , _interval(0.0f)
    , _aborted(false)
    

    设置定时器Timer()

    void Timer::setupTimerWithInterval(float seconds, unsigned int repeat, float delay)
    {
        _elapsed = -1;  //=-1表示是第一次进入函数,后面的再Update函数中会有初始化操作
        _interval = seconds;
        _delay = delay;
        _useDelay = (_delay > 0.0f) ? true : false;
        _repeat = repeat;
        _runForever = (_repeat == CC_REPEAT_FOREVER) ? true : false;  //CC_REPEAT_FOREVER == -1
        _timesExecuted = 0;
    }
    
    
    void Timer::update(float dt)
    {
        if (_elapsed == -1) //表示第一次进入Update方法,进行初始化
        {
            _elapsed = 0;         //已执行时间
            _timesExecuted = 0;   //执行次数
            return;
        }
    
        // accumulate elapsed time
        _elapsed += dt;  //记录累计度过的时间
        
        // deal with delay
        if (_useDelay)
        {
            if (_elapsed < _delay) // 还没有完成延时
            {
                return;
            }
            _timesExecuted += 1; // important to increment before call trigger
            trigger(_delay);   //      【回调函数】
            _elapsed = _elapsed - _delay; //此时记录的是开始执行之后度过的时间
            _useDelay = false; //延迟结束
            // after delay, the rest time should compare with interval
            if (isExhausted()) //不永远执行并且已经执行完了重复次数
            {    //unschedule timer
                cancel(); 
                return;
            }
        }
        
        // if _interval == 0, should trigger once every frame
        float interval = (_interval > 0) ? _interval : _elapsed; //正常来说interval都是大于零的,如果interval小于零,那就使用度过的时间来代替间隔时间
      //如果度过的时间比间隔要大才会执行
        while ((_elapsed >= interval) && !_aborted) 
        {
            _timesExecuted += 1;  // important to increment before call trigger
            trigger(interval);    //      【回调函数】
            _elapsed -= interval; //记录剩余时间
    
            if (isExhausted())    //不永远执行并且已经执行完了重复次数
            {
                cancel();
                break;
            }
    
            if (_elapsed <= 0.f) //间隔时间等于度过的时间
            {
                break;
            }
        }
    }
    

    一些成员函数

    bool TimerTargetSelector::initWithSelector(Scheduler* scheduler, SEL_SCHEDULE selector, Ref* target, float seconds, unsigned int repeat, float delay)
    {
        _scheduler = scheduler;
        _target = target;
        _selector = selector;  //selector没有set方法,通过此方法来初始化
        setupTimerWithInterval(seconds, repeat, delay);
        return true;
    }
    
    void TimerTargetSelector::trigger(float dt) //调用回调函数
    {
        if (_target && _selector)
        {
            (_target->*_selector)(dt);
        }
    }
    
    void TimerTargetSelector::cancel()
    {
        _scheduler->unschedule(_selector, _target);
    }
    
    class CC_DLL TimerTargetCallback : public Timer
    {
    public:
       TimerTargetCallback();
       
       // Initializes a timer with a target, a lambda and an interval in seconds, repeat in number of times to repeat, delay in seconds.
       bool initWithCallback(Scheduler* scheduler, const ccSchedulerFunc& callback, void *target, const std::string& key, float seconds, unsigned int repeat, float delay);
       
       const ccSchedulerFunc& getCallback() const { return _callback; }
       const std::string& getKey() const { return _key; }
       
       virtual void trigger(float dt) override;
       virtual void cancel() override;
       
    protected:
       void* _target;
       ccSchedulerFunc _callback;
       std::string _key;
    };
    //初始化
    bool TimerTargetCallback::initWithCallback(Scheduler* scheduler, const ccSchedulerFunc& callback, void *target, const std::string& key, float seconds, unsigned int repeat, float delay)
    {
       _scheduler = scheduler;
       _target = target;
       _callback = callback;
       _key = key;
       setupTimerWithInterval(seconds, repeat, delay);
       return true;
    }
    //调用回调函数
    void TimerTargetCallback::trigger(float dt)
    {
       if (_callback)
       {
           _callback(dt);
       }
    }
    //
    void TimerTargetCallback::cancel()
    {
       _scheduler->unschedule(_key, _target);
    

    Scheduler()

    经常使用的调度器是:

    schedulerUpdate()

    scheduler(SEL_SCHEDULE selector, float interval, unsigned int repeat, float delay)

    scheduleOnce(SEL_SCHEDULE selector, float delay)

    变量

    pause:启用或暂停此方法。暂停(false),启用(true)

    interval:每隔“interval”秒调用一次方法,如果为0,则每一帧都调用,当为0时,建议使用schedulerUpdate。

    repeat:触发一次事件后还会触发的次数,为0时触发一次

    delay:延迟多少秒,是指在触发之前的延迟,在触发之后叫间隔,使用interval设置

    key:用于取消定时器

    初始化

    typedef struct _listEntry
    {
        struct _listEntry   *prev, *next;
        ccSchedulerFunc     callback;
        void                *target;
        int                 priority;
        bool                paused;
        bool                markedForDeletion; // selector will no longer be called and entry will be removed at end of the next tick
    } tListEntry;
    
    //内置的update定时器
    typedef struct _hashUpdateEntry
    {
        tListEntry          **list;        // Which list does it belong to ?
        tListEntry          *entry;        // entry in the list
        void                *target;
        ccSchedulerFunc     callback;
        UT_hash_handle      hh;
    } tHashUpdateEntry;
     
    // 自定义定时器
    typedef struct _hashSelectorEntry
    {
        ccArray             *timers;
        void                *target;
        int                 timerIndex;
        Timer               *currentTimer;
        bool                currentTimerSalvaged;
        bool                paused;
        UT_hash_handle      hh;
    } tHashTimerEntry;
    float _timeScale;
        struct _listEntry *_updatesNegList;        // list of priority < 0 三种优先级
        struct _listEntry *_updates0List;            // list priority == 0
        struct _listEntry *_updatesPosList;        // list priority > 0
        struct _hashUpdateEntry *_hashForUpdates; // hash used to fetch quickly the list entries for pause,delete,etc
        std::vector<struct _listEntry *> _updateDeleteVector; // the vector holds list entries that needs to be deleted after update
        // Used for "selectors with interval"
        struct _hashSelectorEntry *_hashForTimers;
        struct _hashSelectorEntry *_currentTarget;
        bool _currentTargetSalvaged;
        // If true unschedule will not remove anything from a hash. Elements will only be marked for deletion.
        bool _updateHashLocked;
    
    //初始化
    Scheduler::Scheduler(void)
    : _timeScale(1.0f) //播放速度为1.0
    , _updatesNegList(nullptr) //
    , _updates0List(nullptr)
    , _updatesPosList(nullptr)
    , _hashForUpdates(nullptr)
    , _hashForTimers(nullptr)
    , _currentTarget(nullptr)
    , _currentTargetSalvaged(false)
    , _updateHashLocked(false)
    #if CC_ENABLE_SCRIPT_BINDING
    , _scriptHandlerEntries(20)
    #endif
    {
        // I don't expect to have more than 30 functions to all per frame
       //预开辟30个空间,且不希望超过30个函数
        _functionsToPerform.reserve(30); 
    }
    

    哈希表

    #include "base/uthash.h"
    typedef struct UT_hash_handle {
       struct UT_hash_table *tbl;
       void *prev;                       /* prev element in app order      */
       void *next;                       /* next element in app order      */
       struct UT_hash_handle *hh_prev;   /* previous hh in bucket order    */
       struct UT_hash_handle *hh_next;   /* next hh in bucket order        */
       void *key;                        /* ptr to enclosing struct's key  */
       unsigned keylen;                  /* enclosing struct's key len     */
       unsigned hashv;                   /* result of hash-fcn(key)        */
    } UT_hash_handle;
    
    HASH_FIND_PTR(head,findptr,out)
    HASH_ADD_PTR(head,ptrfield,add) 
    HASH_DEL(head,delptr) 
      
    //不同优先级的update定时器的双向链表
    typedef struct _listEntry
    {
        struct _listEntry   *prev, *next;
        ccSchedulerFunc     callback;
        void                *target;
        int                 priority;
        bool                paused;
        bool                markedForDeletion; // selector will no longer be called and entry will be removed at end of the next tick
    } tListEntry;
    
    //内置的update定时器
    typedef struct _hashUpdateEntry
    {
        tListEntry          **list;        // Which list does it belong to ?
        tListEntry          *entry;        // entry in the list
        void                *target;
        ccSchedulerFunc     callback;
        UT_hash_handle      hh;
    } tHashUpdateEntry;
    
    //自定义的定时器
    typedef struct _hashSelectorEntry
    {
        ccArray             *timers; //如下
        void                *target;
        int                 timerIndex;
        Timer               *currentTimer;
        bool                paused;
        UT_hash_handle      hh;
    } tHa
    typedef struct _ccArray {
    	ssize_t num, max;
    	Ref** arr;
    } ccArray;
    void ccArrayAppendObject(ccArray *arr, Ref* object)
    {
        CCASSERT(object != nullptr, "Invalid parameter!");
        object->retain();
    		arr->arr[arr->num] = object;
    		arr->num++;//序号+1
    }
    

    构造函数schedule()

    //重载版本① 更新选择器 //Ref *target 
    void Scheduler::schedule(SEL_SCHEDULE selector, Ref *target, float interval, unsigned int repeat, float delay, bool paused)
    {
        CCASSERT(target, "Argument target must be non-nullptr");
       
      //用来记录一个Ref对象加载的所有timer
        tHashTimerEntry *element = nullptr; 
      
      //_hashForTimers是用来记录tHashTimerEntry头结点的指针
      //在_hashForTimers链表中查找与target相等的元素,返回一个element
      //#define HASH_FIND_PTR(head,findptr,out)
        HASH_FIND_PTR(_hashForTimers, &target, element);
        
      //判断有没有找到
        if (! element) 
        {
          //为空则先分配空间
            element = (tHashTimerEntry *)calloc(sizeof(*element), 1);
          //把链表的target指向形参target(把形参的target加入链表)
            element->target = target; 
            
          //再次查找获取链表中的”element“
            HASH_ADD_PTR(_hashForTimers, target, element);
            +
            // Is this the 1st element ? Then set the pause level to all the selectors of this target
              //给获取到的element设置paused的状态
            element->paused = paused; 
        }
      //target已经加入链表了,判断paused的状态是否设定成功
        else 
        {
            CCASSERT(element->paused == paused, "element's paused should be paused.");
        }
        
      //判断定时器列表的状态,如果为空则分配空间
        if (element->timers == nullptr)
        {
            element->timers = ccArrayNew(10);
        }
        else
        {
          //循环定时器结构中的成员
            for (int i = 0; i < element->timers->num; ++i) 
            {
              //获取其中的定时器对象
                TimerTargetSelector *timer = dynamic_cast<TimerTargetSelector*>(element->timers->arr[i]);
                
              //如果定义过定时器,则重新设置interval, repeat, delay
                if (timer && !timer->isExhausted() && selector == timer->getSelector())
                {
                    CCLOG("CCScheduler#schedule. Reiniting timer with interval %.4f, repeat %u, delay %.4f", interval, repeat, delay);
                    timer->setupTimerWithInterval(interval, repeat, delay);
                    return;
                }
            }
          //检查ccArray的内存,确定可以再添加一个timers
            ccArrayEnsureExtraCapacity(element->timers, 1); 
        }
        
      //创建了一个新的TimerTargetSelector对象(timer),用上面处理过的实参对其初始化,并且加到定时器列表(timers)中
        TimerTargetSelector *timer = new (std::nothrow) TimerTargetSelector();
        timer->initWithSelector(this, selector, target, interval, repeat, delay);
        ccArrayAppendObject(element->timers, timer);//object->retain();
        timer->release();
    }
    
    //重载版本②//使用回调函数callback 多了 形参key和repeat //自定义选择器 void *target
    void Scheduler::schedule(const ccSchedulerFunc& callback, void *target, float interval, unsigned int repeat, float delay, bool paused, const std::string& key)
    {
        CCASSERT(target, "Argument target must be non-nullptr");
        CCASSERT(!key.empty(), "key should not be empty!");
    
        tHashTimerEntry *element = nullptr;
        HASH_FIND_PTR(_hashForTimers, &target, element);
    
        if (! element)
        {
            element = (tHashTimerEntry *)calloc(sizeof(*element), 1);
            element->target = target;
    
            HASH_ADD_PTR(_hashForTimers, target, element);
    
            // Is this the 1st element ? Then set the pause level to all the selectors of this target
            element->paused = paused;
        }
        else
        {
            CCASSERT(element->paused == paused, "element's paused should be paused!");
        }
    
        if (element->timers == nullptr)
        {
            element->timers = ccArrayNew(10);
        }
        else 
        {
            for (int i = 0; i < element->timers->num; ++i)
            {
                TimerTargetCallback *timer = dynamic_cast<TimerTargetCallback*>(element->timers->arr[i]);
    
                if (timer && !timer->isExhausted() && key == timer->getKey())
                {
                    CCLOG("CCScheduler#schedule. Reiniting timer with interval %.4f, repeat %u, delay %.4f", interval, repeat, delay);
                    timer->setupTimerWithInterval(interval, repeat, delay);
                    return;
                }
            }
            ccArrayEnsureExtraCapacity(element->timers, 1);
        }
    
        TimerTargetCallback *timer = new (std::nothrow) TimerTargetCallback();
        timer->initWithCallback(this, callback, target, key, interval, repeat, delay);
        ccArrayAppendObject(element->timers, timer);
        timer->release();
    }
    
    //重载版本③ //永远执行   repeat = CC_REPEAT_FOREVER
    void Scheduler::schedule(const ccSchedulerFunc& callback, void *target, float interval, bool paused, const std::string& key)
    {
        this->schedule(callback, target, interval, CC_REPEAT_FOREVER, 0.0f, paused, key);
    }
    //重载版本④ //永远执行  repeat = CC_REPEAT_FOREVER
    void Scheduler::schedule(SEL_SCHEDULE selector, Ref *target, float interval, bool paused)
    {
        this->schedule(selector, target, interval, CC_REPEAT_FOREVER, 0.0f, paused);
    }
    

    开启定时器Update()

    /*
    void Node::scheduleUpdate()
    {
        scheduleUpdateWithPriority(0);
    }
    */
    //每帧执行一次,默认优先级为0,优先级越小越先执行
    void Node::scheduleUpdateWithPriority(int priority)
    {
        _scheduler->scheduleUpdate(this, priority, !_running);
    }
    //默认优先级为0,在所有自定义方法之前执行
    template <class T>
        void scheduleUpdate(T *target, int priority, bool paused)
        {
            this->schedulePerFrame([target](float dt){
                target->update(dt);
            }, target, priority, paused);
        }
    void Scheduler::schedulePerFrame(const ccSchedulerFunc& callback, void *target, int priority, bool paused)
    {
      	//定义一个hash链表对象
        tHashUpdateEntry *hashElement = nullptr;
      	//查找target,结果通过hashElement返回
        HASH_FIND_PTR(_hashForUpdates, &target, hashElement);
      	//如果找到了
        if (hashElement)
        {
            // change priority: should unschedule it first
          //检查优先级是否已经被修改,如果还未修改,先取消修改的计划;
          //如果已经被修改,则提示不要重复执行修改操作
            if (hashElement->entry->priority != priority)
            {
                unscheduleUpdate(target);
            }
            else
            {
                // don't add it again
                CCLOG("warning: don't update it again");
                return;
            }
        }
    
        // most of the updates are going to be 0, that's way there
        // is an special list for updates with priority 0
     		//然后将其加入到对应优先级的链表中
        if (priority == 0)
        {
            appendIn(&_updates0List, callback, target, paused);//如下
        }
        else if (priority < 0)
        {
            priorityIn(&_updatesNegList, callback, target, priority, paused);//如下
        }
        else
        {
            // priority > 0
            priorityIn(&_updatesPosList, callback, target, priority, paused);
        }
    }
    //appendIn()用于添加默认优先级的
    void Scheduler::appendIn(_listEntry **list, const ccSchedulerFunc& callback, void *target, bool paused)
    {
      //新建优先级更新链表
        tListEntry *listElement = new (std::nothrow) tListEntry();
    
        listElement->callback = callback;
        listElement->target = target;
        listElement->paused = paused;
        listElement->priority = 0;
        listElement->markedForDeletion = false;
    
      //把listElement加到优先级为0的list中
        DL_APPEND(*list, listElement);
    
        // update hash entry for quicker access
      //创建一个hash链表指针对象
        tHashUpdateEntry *hashElement = (tHashUpdateEntry *)calloc(sizeof(*hashElement), 1);
        hashElement->target = target;
        hashElement->list = list;
        hashElement->entry = listElement;
        memset(&hashElement->hh, 0, sizeof(hashElement->hh));
     //把hashElement添加到_hashForUpdates中
        HASH_ADD_PTR(_hashForUpdates, target, hashElement);
    }
    //priorityIn()用于添加指定优先级
    void Scheduler::priorityIn(tListEntry **list, const ccSchedulerFunc& callback, void *target, int priority, bool paused)
    {
      //同上
        tListEntry *listElement = new (std::nothrow) tListEntry();
    
        listElement->callback = callback;
        listElement->target = target;
        listElement->priority = priority;
        listElement->paused = paused;
        listElement->next = listElement->prev = nullptr;
        listElement->markedForDeletion = false;
    
        //判断优先级<0的链表是不是空的
        if (! *list)
        {
          //是空的直接添加
            DL_APPEND(*list, listElement);
        }
        else
        {
          //设置一个add表示还未添加完成
            bool added = false;
    
            for (tListEntry *element = *list; element; element = element->next)
            {
              //如果添加的元素的优先级 < 被循环到的元素的优先级,
              //说明插入的元素优先级更高,则会被插入到循环的这个元素之前
                if (priority < element->priority)
                {
                    if (element == *list)
                    {
                        DL_PREPEND(*list, listElement);
                    }
                    else
                    {
                      //tListEntry *element = *list的备选路径
                        listElement->next = element;
                        listElement->prev = element->prev;
    
                        element->prev->next = listElement;
                        element->prev = listElement;
                    }
    							//添加完成了     
                    added = true;
                    break;
                }
            }
    
            // Not added? priority has the higher value. Append it.
          //是否添加完成(未完成说明插入的元素在链表中的优先级最低,插入到链表最后) 
          if (! added)
            {
                DL_APPEND(*list, listElement);
            }
        }
    
        // update hash entry for quick access
      //同上
        tHashUpdateEntry *hashElement = (tHashUpdateEntry *)calloc(sizeof(*hashElement), 1);
        hashElement->target = target;
        hashElement->list = list;
        hashElement->entry = listElement;
        memset(&hashElement->hh, 0, sizeof(hashElement->hh));
        HASH_ADD_PTR(_hashForUpdates, target, hashElement);
    }
    

    析构函数~Update()

    void Scheduler::unschedule(const std::string &key, void *target)
    {
        // explicit handle nil arguments when removing an object
        if (target == nullptr || key.empty())
        {
            return;
        }
    
        //CCASSERT(target);
        //CCASSERT(selector);
    
        tHashTimerEntry *element = nullptr;
        HASH_FIND_PTR(_hashForTimers, &target, element);
    
        if (element)
        {
            for (int i = 0; i < element->timers->num; ++i)
            {
                TimerTargetCallback *timer = dynamic_cast<TimerTargetCallback*>(element->timers->arr[i]);
    						//找到要移除的timer
                if (timer && key == timer->getKey())
                {
                    if (timer == element->currentTimer && (! timer->isAborted()))
                    {
                        timer->retain();//+1
                        timer->setAborted();//设置延迟释放,下面还要继续访问
                    }
    								//在这里调用CC_SAFE_RELEASE -1
                    ccArrayRemoveObjectAtIndex(element->timers, i, true);
    
                    // update timerIndex in case we are in tick:, looping over the actions
                	  //个数-1
                    if (element->timerIndex >= i)
                    {
                        element->timerIndex--;
                    }
    								//timers里面没有timer了
                    if (element->timers->num == 0)
                    {
                      	//标记需要被删除,在刷新函数中执行移除操作
                        if (_currentTarget == element)
                        {
                            _currentTargetSalvaged = true;
                        }
                        else
                        {
                          //链表中移除  移除之后是安全的了,回到Scheduler::update()中再release()释放
                            removeHashElement(element);
                        }
                    }
    
                    return;
                }
            }
        }
    }
    

    Update()

    void Scheduler::update(float dt)
    {
      //状态锁
        _updateHashLocked = true;
    	//调整时间速率
        if (_timeScale != 1.0f)
        {
            dt *= _timeScale;
        }
    
        //
        // Selector callbacks
        //
    
        // Iterate over all the Updates' selectors
        tListEntry *entry, *tmp;
    
        // updates with priority < 0
      	//先执行优先级高的 priority < 0
        DL_FOREACH_SAFE(_updatesNegList, entry, tmp)
        {
          //对没有暂停的和没有被标记需要删除的执行回调函数
            if ((! entry->paused) && (! entry->markedForDeletion))
            {
                entry->callback(dt);
            }
        }
    
        // updates with priority == 0
        DL_FOREACH_SAFE(_updates0List, entry, tmp)
        {
            if ((! entry->paused) && (! entry->markedForDeletion))
            {
                entry->callback(dt);
            }
        }
    
        // updates with priority > 0
        DL_FOREACH_SAFE(_updatesPosList, entry, tmp)
        {
            if ((! entry->paused) && (! entry->markedForDeletion))
            {
                entry->callback(dt);
            }
        }
    
        // Iterate over all the custom selectors
      	//遍历自定义的定时器
        for (tHashTimerEntry *elt = _hashForTimers; elt != nullptr; )
        {
            _currentTarget = elt; //标记执行到了那个target对象
            _currentTargetSalvaged = false; //设置定时器为可用状态
    
            if (! _currentTarget->paused)
            {
                // The 'timers' array may change while inside this loop
              	//遍历当前对象的所有定时器
                for (elt->timerIndex = 0; elt->timerIndex < elt->timers->num; ++(elt->timerIndex))
                {
                  //标记执行到了那个timer对象
                    elt->currentTimer = (Timer*)(elt->timers->arr[elt->timerIndex]);
                  //如果已经被弃用  
                  CCASSERT( !elt->currentTimer->isAborted(),
                        "An aborted timer should not be updated" );
    								//
                    elt->currentTimer->update(dt);//执行定时器的update()!! 在这里执行定时器的回调函数
    								//如果被弃用了就释放它 执行了上面一条语句之后,已经被从链表中移除了,这时候释放才是安全的
                    if (elt->currentTimer->isAborted())
                    {
                        // The currentTimer told the remove itself. To prevent the timer from
                        // accidentally deallocating itself before finishing its step, we retained
                        // it. Now that step is done, it's safe to release it.
                        elt->currentTimer->release();
                    }
    								//当前执行到的timer对象置空
                    elt->currentTimer = nullptr;  
                }
            }
    
            // elt, at this moment, is still valid
            // so it is safe to ask this here (issue #490)
          	//链表继续往后访问
            elt = (tHashTimerEntry *)elt->hh.next;
    
            // only delete currentTarget if no actions were scheduled during the cycle (issue #481)
          	//如果被标记弃用并且里面没有timer了,就移除它(定时器已经执行完成了)
            if (_currentTargetSalvaged && _currentTarget->timers->num == 0)
            {
                removeHashElement(_currentTarget);
            }
        }
     
        // delete all updates that are removed in update
      	//移除所有标记为要删除的update定时器元素
        for (auto &e : _updateDeleteVector)
            delete e;
    		//清空待删除数组
        _updateDeleteVector.clear();
    		
      	//移除状态锁
        _updateHashLocked = false;
      	//执行到的target对象置空
        _currentTarget = nullptr;
    
    #if CC_ENABLE_SCRIPT_BINDING
        //
        // Script callbacks
        //
    
        // Iterate over all the script callbacks
        if (!_scriptHandlerEntries.empty())
        {
            for (auto i = _scriptHandlerEntries.size() - 1; i >= 0; i--)
            {
                SchedulerScriptHandlerEntry* eachEntry = _scriptHandlerEntries.at(i);
                if (eachEntry->isMarkedForDeletion())
                {
                    _scriptHandlerEntries.erase(i);
                }
                else if (!eachEntry->isPaused())
                {
                    eachEntry->getTimer()->update(dt);
                }
            }
        }
    #endif
        //
        // Functions allocated from another thread
        //
    
        // Testing size is faster than locking / unlocking.
        // And almost never there will be functions scheduled to be called.
        if( !_functionsToPerform.empty() ) {
            _performMutex.lock();
            // fixed #4123: Save the callback functions, they must be invoked after '_performMutex.unlock()', otherwise if new functions are added in callback, it will cause thread deadlock.
            auto temp = std::move(_functionsToPerform);
            _performMutex.unlock();
            
            for (const auto &function : temp) {
                function();
            }
        }
    }
    

    removeUpdateFromHash()

    void Scheduler::unscheduleUpdate(void *target)
    {
        if (target == nullptr)
        {
            return;
        }
    
        tHashUpdateEntry *element = nullptr;
        HASH_FIND_PTR(_hashForUpdates, &target, element);
        if (element)
            this->removeUpdateFromHash(element->entry);										//   
    }
    void Scheduler::removeUpdateFromHash(struct _listEntry *entry)
    {
        tHashUpdateEntry *element = nullptr;
    
        HASH_FIND_PTR(_hashForUpdates, &entry->target, element);
        if (element)
        {
            // list entry
            DL_DELETE(*element->list, element->entry);
            if (!_updateHashLocked)
                CC_SAFE_DELETE(element->entry);
            else
            {
                element->entry->markedForDeletion = true;
                _updateDeleteVector.push_back(element->entry);									//   
            }
    
            // hash entry
            HASH_DEL(_hashForUpdates, element);
            free(element);
        }
    }
    

    一些成员函数

    //通过key和target来判断当前对象是否在定时器中
    bool isScheduled(const std::string& key, const void *target) const;
    //判断条件不同
    bool isScheduled(SEL_SCHEDULE selector, const Ref *target) const;
    //恢复一个对象的定时器
    void resumeTarget(void *target);
    //查询一个对象的定时器装状态
    bool isTargetPaused(void *target);
    //暂停所有的定时器
    std::set<void*> pauseAllTargets();
    //恢复所有的定时器
    void resumeTargets(const std::set<void*>& targetsToResume);
    
    

    补充

    1、为什么使用colloc不使用malloc?
    究其根本是malloc和colloc区别的原因,
    使用
    malloc:(type*)malloc(size) 分配一个size大小的内存空间返回type类型的指针指向内存的首地址
    colloc:(type*)colloc(n,size) 分配n个size大小的连续内存空间返回type类型的指针指向第一个内存的首地址
    最大的区别是:malloc只分配内存空间不做初始化,原先内存中的数据依然存在,可能会造成数据错误;colloc分配空间后进行初始化,将分配的空间都初始化为0,避免了数据错误。
    
    2、std::move
    std::string str = "Hello";
    std::vector<std::string> v;
    
    v.push_back(str); 
    std::cout<<v[0]; //输出hello 
    std::cout<<str; //输出hello
    
    v.push_back(std::move(str));
    std::cout<<v[0]; //输出hello 
    std::cout<<v[1]; //输出hello
    std::cout<<str; //输出为空
    
    
    
  • 相关阅读:
    qmake理解(还可以加入Lex Yacc文件)
    如何在Qt 4程序中优化布局结构(表格讲解,很清楚)
    QList内存释放(看它内部存储的是否是Object,另外还有qDeleteAll)
    Qt工具知多少(一目了然)
    分享个人如何DIY网站的经验
    推荐10款免费而优秀的图表插件
    异步上传文件
    JSON.stringify 方法
    Value Object(值对象)如何使用 EF 进行正确映射
    领域驱动设计(DDD)
  • 原文地址:https://www.cnblogs.com/sakuraneo/p/11992059.html
Copyright © 2020-2023  润新知