RecurrentTimer代码分析

下面的代码是Android VehicleHal中一个定时任务工具:

/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef android_hardware_automotive_vehicle_V2_0_RecurrentTimer_H_
#define android_hardware_automotive_vehicle_V2_0_RecurrentTimer_H_

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

/**
 * This class allows to specify multiple time intervals to receive
 * notifications. A single thread is used internally.
 */
class RecurrentTimer {
private:
    using Nanos = std::chrono::nanoseconds;
    using Clock = std::chrono::steady_clock;
    using TimePoint = std::chrono::time_point<Clock, Nanos>;
public:
    using Action = std::function<void(const std::vector<int32_t>& cookies)>;

    RecurrentTimer(const Action& action) : mAction(action) {
        mTimerThread = std::thread(&RecurrentTimer::loop, this, action);
    }

    virtual ~RecurrentTimer() {
        stop();
    }

    /**
     * Registers recurrent event for a given interval. Registred events are distinguished by
     * cookies thus calling this method multiple times with the same cookie will override the
     * interval provided before.
     */
    void registerRecurrentEvent(std::chrono::nanoseconds interval, int32_t cookie) {
        TimePoint now = Clock::now();
        // 确保所有事件的触发时间都对齐到一个共同的时间点。
        //换句话说,系统会计算出所有周期性任务的最接近的触发时间点,使得多个任务在同一时刻触发,而不是错开执行。
        //假设我们有两个周期性的任务,一个周期是 1ms,另一个周期是 2ms。
        //在正常的情况下,这两个任务不会在同一时间点触发,除非它们的触发时间被对齐。
        //通过对齐机制,两个任务(1ms 和 2ms)会在某些特定的时刻(每第二次唤醒时)都被触发。
        //这样,两个不同周期的任务就能在某些时刻同步执行,而不会出现错开。
        TimePoint absoluteTime = now - Nanos(now.time_since_epoch().count() % interval.count());

        {
            std::lock_guard<std::mutex> g(mLock);
            mCookieToEventsMap[cookie] = { interval, cookie, absoluteTime };
        }
        mCond.notify_one();
    }

    void unregisterRecurrentEvent(int32_t cookie) {
        {
            std::lock_guard<std::mutex> g(mLock);
            mCookieToEventsMap.erase(cookie);
        }
        mCond.notify_one();
    }


private:

    struct RecurrentEvent {
        Nanos interval;//任务的触发间隔时间(单位是纳秒)
        int32_t cookie;//任务的标识符,用于区分不同的任务
        TimePoint absoluteTime;  // 任务的下次触发时间

        void updateNextEventTime(TimePoint now) {
            //当前时间与任务下一次触发时间之间,已经过去了多少个完整的周期。
            int intervalMultiplier = (now - absoluteTime) / interval;
            //如果当前时间还没有到达下一次任务触发时间(即 now 小于 absoluteTime),那么 (now - absoluteTime) 会是负数,此时 intervalMultiplier 会小于或等于 0。
			//为了避免出现负值,代码将 intervalMultiplier 强制设置为 1,即使当前时间还没有到达下一次任务触发时间,它也会确保至少执行一次任务
            if (intervalMultiplier <= 0) intervalMultiplier = 1;
            //任务周期是 100ms,当前时间是 550ms,而任务的上一轮触发时间是 500ms。则 (550ms - 500ms) / 100ms = 0.5,我们将 intervalMultiplier 设置为 1,下一次触发时间将是 600ms
            absoluteTime += intervalMultiplier * interval;
        }
    };

    void loop(const Action& action) {
        static constexpr auto kInvalidTime = TimePoint(Nanos::max());

        std::vector<int32_t> cookies;

        while (!mStopRequested) {
            auto now = Clock::now();
            auto nextEventTime = kInvalidTime;
            cookies.clear();

            {
                std::unique_lock<std::mutex> g(mLock);
				//遍历所有事件,检查哪些事件已到触发时间
                for (auto&& it : mCookieToEventsMap) {
                    RecurrentEvent& event = it.second;
                    //当线程发现有事件到期(absoluteTime <= now)时,就执行回调并更新其下次触发时间(updateNextEventTime)。然后再次计算新的 nextEventTime 并继续等待。
                    if (event.absoluteTime <= now) {
                        event.updateNextEventTime(now);
                        cookies.push_back(event.cookie);
                    }
					//  找出最早的下次事件触发时间,用于下一次wait
                    if (nextEventTime > event.absoluteTime) {
                        nextEventTime = event.absoluteTime;
                    }
                }
            }
			//执行回调(一次可能触发多个事件)
            if (cookies.size() != 0) {
                action(cookies);
            }

            std::unique_lock<std::mutex> g(mLock);
            // mStopRequested might be set to true after we enter the loop. Must check inside
            // the lock to make sure the value will not change before we start the wait.
            if (mStopRequested) {
                return;
            }
            //等待下一个触发时间或被唤醒
            mCond.wait_until(g, nextEventTime);  // nextEventTime can be nanoseconds::max()
        }
    }

    void stop() {
        {
            std::lock_guard<std::mutex> g(mLock);
            mCookieToEventsMap.clear();
            // Even though this is atomic, this must be set inside the lock to make sure we will
            // not change this after we check mStopRequested, but before we start the wait.
            mStopRequested = true;
        }
        mCond.notify_one();
        if (mTimerThread.joinable()) {
            mTimerThread.join();
        }
    }

private:
    mutable std::mutex mLock;
    std::thread mTimerThread;
    std::condition_variable mCond;
    std::atomic_bool mStopRequested { false };
    Action mAction;
    std::unordered_map<int32_t, RecurrentEvent> mCookieToEventsMap;
};


#endif  // android_hardware_automotive_vehicle_V2_0_RecurrentTimer_H

代码分析:

TimePoint now = Clock::now();
TimePoint absoluteTime = now - Nanos(now.time_since_epoch().count() % interval.count());

  1. 对当前的时间(now.time_since_epoch().count())与任务周期(interval.count())进行求余。也就是说,它计算出当前时间距离最近的周期边界的“偏移量”。

  2. 比如,如果 now 是 550ms,而 interval 是 100ms,那么 absoluteTime = 550ms - 50ms = 500ms,即 500ms 是下一个周期的触发时间点.

你可能感兴趣的:(c++,c++,android)