深入解析evpp项目中的自管理定时器实现
前言
在evpp这个基于C++11的高性能网络库中,实现了一个非常精巧的自管理定时器功能。这个定时器不仅能够自动执行预设的回调函数,还能在不需要时自动销毁自己,极大地简化了开发者的使用负担。本文将深入剖析这一功能的实现原理和技术细节。
基础概念
定时器的基本需求
一个完善的定时器通常需要满足以下基本需求:
- 能够在指定时间后触发回调
- 能够被取消
- 能够自动管理生命周期
- 支持周期性触发
关键技术点
实现这样一个定时器需要解决几个关键技术问题:
- 如何确保定时器对象在回调执行期间不会被意外销毁
- 如何实现定时器的自我销毁
- 如何支持定时器的取消操作
- 如何实现周期性定时器
基础实现
最简单的定时器
最基础的定时器实现非常简单:
class InvokeTimer {
public:
InvokeTimer(event_base* evloop, double timeout_ms, const std::function<void()>& f);
~InvokeTimer();
void Start();
private:
event_base* loop_;
double timeout_ms_;
std::function<void()> functor_;
std::shared_ptr<TimerEventWatcher> timer_;
};
这种实现方式虽然简单,但存在明显的问题:定时器的生命周期需要由调用者管理,容易造成内存泄漏或提前销毁的问题。
自我管理实现
自我销毁机制
为了实现定时器的自我管理,我们可以在回调函数中执行delete this
:
void InvokeTimer::OnTimerTriggered() {
functor_();
delete this;
}
这种方式虽然解决了生命周期管理问题,但存在以下限制:
- 对象必须在堆上创建
- 无法在定时器触发前取消
- 无法支持周期性定时器
智能指针解决方案
使用shared_ptr和enable_shared_from_this
更完善的解决方案是使用shared_ptr
和enable_shared_from_this
:
class InvokeTimer : public std::enable_shared_from_this<InvokeTimer> {
public:
static std::shared_ptr<InvokeTimer> Create(event_base* evloop,
double timeout_ms,
const std::function<void()>& f);
private:
std::shared_ptr<InvokeTimer> self_; // 持有自身的引用
};
这种实现的关键点在于:
- 定时器对象持有自身的
shared_ptr
引用 - 在回调完成后再释放这个引用
- 支持外部通过
shared_ptr
持有定时器
取消机制实现
基于shared_ptr
的实现可以很方便地支持取消操作:
void InvokeTimer::Cancel() {
if (timer_) {
timer_->Cancel();
}
}
取消时会触发取消回调,然后释放自身引用:
void InvokeTimer::OnCanceled() {
if (cancel_callback_) {
cancel_callback_();
}
self_.reset(); // 释放自身引用
}
周期性定时器实现
周期性触发机制
在回调函数中重新启动定时器即可实现周期性触发:
void InvokeTimer::OnTimerTriggered() {
functor_();
if (periodic_) {
timer_->AsyncWait(); // 重新启动定时器
} else {
self_.reset(); // 单次定时器则释放自身
}
}
实现细节分析
引用计数管理
整个实现中最关键的部分是引用计数的管理:
- 创建时:
self_ = shared_from_this()
增加引用计数 - 触发或取消时:
self_.reset()
减少引用计数 - 外部持有
shared_ptr
也会影响引用计数
线程安全性考虑
由于libevent本身是线程安全的,且shared_ptr
的引用计数操作是原子的,因此这个实现在多线程环境下也是安全的。
使用示例
基本使用
auto timer = InvokeTimer::Create(base, 1000.0, []{
std::cout << "Timer triggered" << std::endl;
});
timer->Start();
周期性定时器
auto timer = InvokeTimer::Create(base, 1000.0, []{
std::cout << "Periodic timer" << std::endl;
}, true);
timer->Start();
取消定时器
auto timer = InvokeTimer::Create(base, 1000.0, []{
std::cout << "This won't be printed" << std::endl;
});
timer->Start();
// ...
timer->Cancel();
性能考量
这种实现方式的性能特点:
- 创建和销毁涉及
shared_ptr
操作,有一定开销 - 定时器触发时只有一次函数调用开销
- 内存占用较小,只有一个
shared_ptr
和几个基本成员
总结
evpp中的自管理定时器实现展示了C++11智能指针的强大能力,通过shared_ptr
和enable_shared_from_this
的巧妙组合,实现了既安全又易用的定时器功能。这种模式不仅适用于定时器,也可以推广到其他需要自我管理的异步对象实现中。
对于开发者来说,理解这种实现方式的原理和细节,有助于在自己的项目中实现类似的功能,或者更好地使用evpp提供的定时器功能。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考