文章目录
-
- 全流程实现博客链接
- 前引
- (二十)---- C++ High-Performance WebServer源码实现(Timer核心代码部分)
-
- 1、timer.h
- 1、timer.cc
- 2、timerqueue.h
- 2、timerqueue.cc
全流程实现博客链接
从零开始自制实现C++ High-Performance WebServer 全流程记录(基于muduo网络库)
前引
还有两个Timer
和Logging
(二十)---- C++ High-Performance WebServer源码实现(Timer核心代码部分)
1、timer.h
#ifndef TINY_MUDUO_TIMER_H_
#define TINY_MUDUO_TIMER_H_#include <functional>#include "timestamp.h"
#include "noncopyable.h"namespace tiny_muduo {
class Timer : public NonCopyAble {
public:typedef std::function<void()> BasicFunc;Timer(Timestamp timestamp, BasicFunc&& cb, double interval);void Restart(Timestamp now) {
expiration_ = Timestamp::AddTime(now, interval_);}void Run() const {
callback_();}Timestamp expiration() const {
return expiration_; }bool repeat() const {
return repeat_; }private:Timestamp expiration_; BasicFunc callback_;double interval_; bool repeat_;
};} // namespace tiny_muduo#endif
1、timer.cc
#include "timer.h"#include <utility>using namespace tiny_muduo;Timer::Timer(Timestamp expiration, BasicFunc&& cb, double interval = 0.0): expiration_(expiration),callback_(std::move(cb)),interval_(interval),repeat_(interval > 0.0) {
}
2、timerqueue.h
#ifndef TINY_MUDUO_TIMERQUEUE_H_
#define TINY_MUDUO_TIMERQUEUE_H_#include <unistd.h>
#include <sys/timerfd.h>#include <set>
#include <vector>
#include <memory>
#include <utility>
#include <functional>#include "timer.h"
#include "timestamp.h"
#include "noncopyable.h"
#include "logging.h"namespace tiny_muduo {
class EventLoop;
class Channel;class TimerQueue : public NonCopyAble {
public:typedef std::function<void()> BasicFunc;TimerQueue(EventLoop* loop);~TimerQueue();void ReadTimerFd() {
uint64_t read_byte;ssize_t readn = ::read(timerfd_, &read_byte, sizeof(read_byte));if (readn != sizeof(read_byte)) {
LOG_ERROR << "TimerQueue::ReadTimerFd read_size < 0";}}void HandleRead() {
ReadTimerFd();Timestamp expiration_time(Timestamp::Now());active_timers_.clear(); auto end = timers_.lower_bound(TimerPair(Timestamp::Now(), reinterpret_cast<Timer*>(UINTPTR_MAX)));active_timers_.insert(active_timers_.end() , timers_.begin(), end);timers_.erase(timers_.begin(), end);for (const auto& timerpair : active_timers_) {
timerpair.second->Run();} ResetTimers();}void ResetTimers() {
for (auto& timerpair: active_timers_) {
if ((timerpair.second)->repeat()) {
auto timer = timerpair.second;timer->Restart(Timestamp::Now());Insert(timer);} else {
delete timerpair.second;}} if (!timers_.empty()) {
ResetTimer(timers_.begin()->second);}}bool Insert(Timer* timer) {
bool reset_instantly = false;if (timers_.empty() || timer->expiration() < timers_.begin()->first ) {
reset_instantly = true;}timers_.emplace(std::move(TimerPair(timer->expiration(), timer)));return reset_instantly;}void AddTimerInLoop(Timer* timer) {
bool reset_instantly = Insert(timer);if (reset_instantly) {
ResetTimer(timer);}}void ResetTimer(Timer* timer);void AddTimer(Timestamp timestamp, BasicFunc&& cb, double interval);private:typedef std::pair<Timestamp, Timer*> TimerPair;typedef std::set<TimerPair> TimersSet; typedef std::vector<TimerPair> ActiveTimers;EventLoop* loop_;int timerfd_;std::unique_ptr<Channel> channel_; TimersSet timers_;ActiveTimers active_timers_;
};} // namesapce tiny_muduo#endif
2、timerqueue.cc
#include "timerqueue.h"#include <assert.h>
#include <sys/timerfd.h>#include <cstring>#include "channel.h"using namespace tiny_muduo;TimerQueue::TimerQueue(EventLoop* loop): loop_(loop),timerfd_(::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC)),channel_(new Channel(loop_, timerfd_)) {
channel_->SetReadCallback(std::bind(&TimerQueue::HandleRead, this));channel_->EnableReading();
}TimerQueue::~TimerQueue() {
channel_->DisableAll();loop_->Remove(channel_.get());close(timerfd_);for (const auto& timerpair : timers_) {
delete timerpair.second;}
}void TimerQueue::AddTimer(Timestamp timestamp, BasicFunc&& cb, double interval) {
Timer* timer(new Timer(timestamp, std::move(cb), interval));loop_->RunOneFunc(std::bind(&TimerQueue::AddTimerInLoop, this, timer));
}void TimerQueue::ResetTimer(Timer* timer) {
struct itimerspec new_;struct itimerspec old_;memset(&new_, '\0', sizeof(new_));memset(&old_, '\0', sizeof(old_));int64_t micro_seconds_dif = timer->expiration().microseconds() - Timestamp::Now().microseconds();if (micro_seconds_dif < 100) {
micro_seconds_dif = 100;}new_.it_value.tv_sec = static_cast<time_t>(micro_seconds_dif / kMicrosecond2Second);new_.it_value.tv_nsec = static_cast<long>((micro_seconds_dif % kMicrosecond2Second) * 1000);int ret = ::timerfd_settime(timerfd_, 0, &new_, &old_);assert(ret != -1);(void) ret;
}