【FastDDS源码剖析】定时器

PDP、EDP、周期心跳、NACK响应、disable_positive_acks时超时确认机制等等都需要使用定时器。
FastDDS中每个RTPSParticipant都有一个ResourceEvent,每个ResourceEvent有一个自己的线程,当前Participant下创建的定时器TimedEvent都在这个线程中执行。


一、TimedEvent/TimedEventImpl

new TimedEvent(...):创建定时器,此时并没有启动,需要调用restart_timer()。定时器超callback返回false会停止定时器。

    periodic_hb_event_ = new TimedEvent(
        pimpl->getEventResource(),                                     // 获取RTPSParticipant中的ResourceEvent
        [&]() -> bool                                                  // 定时器callback
        {
            return send_periodic_heartbeat();
        },
        TimeConv::Time_t2MilliSecondsDouble(m_times.heartbeatPeriod)); // 定时器周期

update_interval():更新timer周期

bool TimedEvent::update_interval(
        const Duration_t& inter)
{
    return impl_->update_interval(inter);
}

go_ready():如果定时器当前状态是INACTIVE,则转为READY,并返回true,否则返回false。

bool TimedEventImpl::go_ready()
{
    bool returned_value = false;
    StateCode expected = StateCode::INACTIVE;

    if (state_.compare_exchange_strong(expected, StateCode::READY))
    {
        returned_value = true;
    }

    return returned_value;
}

restart_timer():TimedEvent创建时并不会直接启动,调用restart_timer()后才会启动,虽然叫restart,但是可以看到这里先判断是否是go_ready()已经启动的定时器并不会restartservice_.notify(impl_) 参考 ResourceEvent。

void TimedEvent::restart_timer()
{
    if (impl_->go_ready())
    {
        service_.notify(impl_);
    }
}

二、ResourceEvent

notify():将TimedEventImpl放到pending_timers_中,然后通知线程函数event_service()

void ResourceEvent::notify(
        TimedEventImpl* event)
{
    std::lock_guard<TimedMutex> lock(mutex_);

    if (register_timer_nts(event))
    {
        // Notify the execution thread that something changed
        cv_.notify_one();
    }
}
bool ResourceEvent::register_timer_nts(
        TimedEventImpl* event)
{
    if (std::find(pending_timers_.begin(), pending_timers_.end(), event) == pending_timers_.end())
    {
        pending_timers_.push_back(event);
        return true;
    }

    return false;
}

event_service():循环更新当前时间,处理定时器do_timer_actions(),等待下次超时时间到next_trigger或者有新的定时器加入。


void ResourceEvent::event_service()
{
    while (!stop_.load())
    {
        // Perform update and execution of timers
        update_current_time();
        do_timer_actions();

        std::unique_lock<TimedMutex> lock(mutex_);

        // If the thread has already been instructed to stop, do it.
        if (stop_.load())
        {
            break;
        }

        // If pending timers exist, there is some work to be done, so no need to wait.
        if (!pending_timers_.empty())
        {
            continue;
        }

        // Allow other threads to manipulate the timer collections while we wait.
        allow_vector_manipulation_ = true;
        cv_manipulation_.notify_all();

        // Wait for the first timer to be triggered
        std::chrono::steady_clock::time_point next_trigger =
                active_timers_.empty() ?
                current_time_ + std::chrono::seconds(1) :
                active_timers_[0]->next_trigger_time();

        auto current_time = std::chrono::steady_clock::now();
        if (current_time > next_trigger)
        {
            next_trigger = current_time + std::chrono::microseconds(10);
        }

        cv_.wait_until(lock, next_trigger);

        // Don't allow other threads to manipulate the timer collections
        allow_vector_manipulation_ = false;
        resize_collections();
    }

    // Thread being stopped. Allow other threads to manipulate the timer collections.
    {
        std::lock_guard<TimedMutex> guard(mutex_);
        allow_vector_manipulation_ = true;
    }
    cv_manipulation_.notify_all();
}

do_timer_actions():先处理新加入的定时器,如果这个定时器不是首次加入,那么他会存在active_timers_中,先移除active_timers_.erase(current_pos),然后更新trigger时间tp->update(current_time_, cancel_time),再插入到有序的active_timers_active_timers_.emplace(low_bound, tp)。接着遍历active_timers_,找到超时的timer执行tp->trigger(current_time_, cancel_time),执行后下次trigger时间会变化,需要重新排序sort_timers(),排序后清理应该取消的timer。


void ResourceEvent::do_timer_actions()
{
    std::chrono::steady_clock::time_point cancel_time =
            current_time_ + std::chrono::hours(24);

    bool did_something = false;

    // Process pending orders
    {
        std::lock_guard<TimedMutex> lock(mutex_);
        for (TimedEventImpl* tp : pending_timers_)
        {
            // Remove item from active timers
            auto current_pos = std::lower_bound(active_timers_.begin(), active_timers_.end(), tp, event_compare);
            current_pos = std::find(current_pos, active_timers_.end(), tp);
            if (current_pos != active_timers_.end())
            {
                active_timers_.erase(current_pos);
            }

            // Update timer info
            if (tp->update(current_time_, cancel_time))
            {
                // Timer has to be activated: add to active timers
                std::vector<TimedEventImpl*>::iterator low_bound;

                // Insert on correct position
                low_bound = std::lower_bound(active_timers_.begin(), active_timers_.end(), tp, event_compare);
                active_timers_.emplace(low_bound, tp);
            }
        }
        pending_timers_.clear();
    }

    // Trigger active timers
    skip_checking_active_timers_.store(false);
    for (TimedEventImpl* tp : active_timers_)
    {
        if (tp->next_trigger_time() <= current_time_)
        {
            did_something = true;
            tp->trigger(current_time_, cancel_time);

            //! skip this iteration as active_timers has been manipulated
            if (skip_checking_active_timers_.load())
            {
                break;
            }
        }
        else
        {
            break;
        }
    }

    // If an action was made, keep active_timers_ sorted
    if (did_something)
    {
        sort_timers();
        active_timers_.erase(
            std::lower_bound(active_timers_.begin(), active_timers_.end(), nullptr,
            [cancel_time](
                TimedEventImpl* a,
                TimedEventImpl* b)
            {
                (void)b;
                return a->next_trigger_time() < cancel_time;
            }),
            active_timers_.end()
            );
    }
}

trigger():调用timer的callback_(),如果返回true,就像周期timer一样,下次interval到的时候再执行,否则像oneshot timer一样,不再执行。这里是将next_trigger_time_设置到cancel_timedo_timer_actions()中会马上清理。


void TimedEventImpl::trigger(
        std::chrono::steady_clock::time_point current_time,
        std::chrono::steady_clock::time_point cancel_time)
{
    if (callback_)
    {
        StateCode expected = StateCode::WAITING;
        if (state_.compare_exchange_strong(expected, StateCode::INACTIVE))
        {

            //Exec
            bool restart = callback_();

            if (restart)
            {
                expected = StateCode::INACTIVE;
                if (state_.compare_exchange_strong(expected, StateCode::WAITING))
                {
                    next_trigger_time_ = current_time + interval_microsec_.load();
                    return;
                }
            }
        }

        next_trigger_time_ = cancel_time;
    }
}

总结

每个RTPSParticipant都有一个线程专门用来处理定时器,这个定时器必须调用restart_timer()才能启动,已启动的定时器即使调用restart_timer()也不会重新计超时时间。Callback返回false,或者调用cancel_timer()停止。

你可能感兴趣的:(FastDDS,源码剖析,网络协议,车载系统,开源软件)