PDP、EDP、周期心跳、NACK响应、disable_positive_acks时超时确认机制等等都需要使用定时器。
FastDDS中每个RTPSParticipant
都有一个ResourceEvent
,每个ResourceEvent
有一个自己的线程,当前Participant下创建的定时器TimedEvent
都在这个线程中执行。
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()
,已经启动的定时器并不会restart。service_.notify(impl_)
参考 ResourceEvent。
void TimedEvent::restart_timer()
{
if (impl_->go_ready())
{
service_.notify(impl_);
}
}
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_time
,do_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()
停止。