一区二区三区电影_国产伦精品一区二区三区视频免费_亚洲欧美国产精品va在线观看_国产精品一二三四

聯系我們 - 廣告服務 - 聯系電話:
您的當前位置: > 關注 > > 正文

何刪除定時器?MyLibco協程網絡庫定時器的設計

來源:CSDN 時間:2023-01-28 13:52:43

時間戳類(基本摘自muduo)

//Timestamp.h

namespace Tattoo{class Timestamp{public:    Timestamp();    explicit Timestamp(int64_t microSecondsSinceEpoch);    void swap(Timestamp &that)    {std::swap(microSecondsSinceEpoch_, that.microSecondsSinceEpoch_);    }    std::string toString() const;    std::string toFormattedString() const;    //微妙大于0就是 valid 的    bool valid() const {return microSecondsSinceEpoch_ > 0; }    int64_t microSecondsSinceEpoch() const {return microSecondsSinceEpoch_; }    //微秒轉化為秒    time_t secondsSinceEpoch() const    {return static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond);    }    //得到現在的時間    static Timestamp now();    //獲取一個無效時間,即時間等于0    static Timestamp invalid();    //一百萬,一微秒等于百萬分之一秒    static const int kMicroSecondsPerSecond = 1000 * 1000;  private:    int64_t microSecondsSinceEpoch_;};// 這里重載 < 號,在下文的multimap 中就會用到inline bool operator<(Timestamp lhs, Timestamp rhs){return lhs.microSecondsSinceEpoch() < rhs.microSecondsSinceEpoch();}inline bool operator==(Timestamp lhs, Timestamp rhs){return lhs.microSecondsSinceEpoch() == rhs.microSecondsSinceEpoch();}將返回兩個事件時間差的秒數,注意單位!inline double timeDifference(Timestamp high, Timestamp low){int64_t diff = high.microSecondsSinceEpoch() - low.microSecondsSinceEpoch();    return static_cast(diff) / Timestamp::kMicroSecondsPerSecond;}//把秒轉化為微秒,構造一個對象,再把它們的時間加起來,構造一個無名臨時對象返回inline Timestamp addTime(Timestamp timestamp, double seconds){int64_t delta = static_cast(seconds * Timestamp::kMicroSecondsPerSecond);    return Timestamp(timestamp.microSecondsSinceEpoch() + delta);}} // namespace Tattoo


(資料圖片僅供參考)

//Timestamp.cpp

using namespace Tattoo;Timestamp::Timestamp()    : microSecondsSinceEpoch_(0){}Timestamp::Timestamp(int64_t microseconds)    : microSecondsSinceEpoch_(microseconds){}std::string Timestamp::toString() const{char buf[32] = {0};    int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond;    int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond;    //PRId64跨平臺打印64位整數,因為int64_t用來表示64位整數,在32位系統中是long long int,64位系統中是long int    //所以打印64位是%ld或%lld,可移植性較差,不如統一同PRID64來打印。    snprintf(buf, sizeof(buf) - 1, "%" PRId64 ".%06" PRId64 "", seconds, microseconds);    return buf;}//把它轉換成一個格式化字符串std::string Timestamp::toFormattedString() const{char buf[32] = {0};    time_t seconds = static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond);    int microseconds = static_cast(microSecondsSinceEpoch_ % kMicroSecondsPerSecond);    struct tm tm_time;    gmtime_r(&seconds, &tm_time);    snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d.%06d",             tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,             tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec,             microseconds);    return buf;}Timestamp Timestamp::now(){struct timeval tv;    gettimeofday(&tv, NULL);     //獲得當前時間,第二個參數是一個時區,當前不需要返回時區,就填空指針    int64_t seconds = tv.tv_sec; //取出秒數    return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec);}Timestamp Timestamp::invalid(){return Timestamp();}

定時器

在這里,我是直接讓協程在一段時間之后喚醒即可(runAfter),至于需不需要 repeat ,這個我也在思考當中,以后了解到了再加吧!!學習也就是一點一點積累的過程啦!!! //Timer.h

/*定時器類*/class Timer{public:    Timer(Timestamp when);    Timestamp expiration() const {return expire_; }    void run() const;    Timestamp expire_; //任務的超時時間    Routine_t *timer_rou_;};

//Timer.cpp

Timer::Timer(Timestamp when)    : timer_rou_(get_curr_routine()), //一個定時器對應一個協程      expire_(when){}void Timer::run() const{cout << "由定時器喚醒對應協程" << endl;    timer_rou_->Resume();}

定時器容器

.h 文件

class TimeHeap{public:    TimeHeap(EventLoop *loop);    ~TimeHeap();    Timer *addTimer(Timestamp when);    void delTimer(Timer *timer);  private:    typedef std::pairEntry;    typedef std::multimapTimerMap;    // 超時之后的可讀回調    void handleRead();    std::vectorgetExpired(Timestamp now);        /* 重置超時的定時器 */    void reset(const std::vector&expired, Timestamp now);    bool insert(Timer *timer);    EventLoop *loop_;    const int timerfd_;    Channel timerfdChannel_;    TimerMap timers_;};

.cpp 文件

namespace Tattoo{namespace detail{//創建 timerfdint createTimerfd(){int timerfd = ::timerfd_create(CLOCK_MONOTONIC,                                   TFD_NONBLOCK | TFD_CLOEXEC);    if (timerfd < 0)    {std::cout << "Failed in timerfd_create" << std::endl;    }    return timerfd;}/* 計算超時時間與當前時間的時間差,并將參數轉換為 api 接受的類型  */struct timespec howMuchTimeFromNow(Timestamp when){/* 微秒數 = 超時時刻微秒數 - 當前時刻微秒數 */    int64_t microseconds = when.microSecondsSinceEpoch() - Timestamp::now().microSecondsSinceEpoch();    if (microseconds < 100)    {microseconds = 100;    }    struct timespec ts; // 轉換成 struct timespec 結構返回    // tv_sec 秒    // tv_nsec 納秒    ts.tv_sec = static_cast(        microseconds / Timestamp::kMicroSecondsPerSecond);    ts.tv_nsec = static_cast(        (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000);    return ts;}/* 讀timerfd,避免定時器事件一直觸發 */void readTimerfd(int timerfd, Timestamp now){uint64_t howmany;    ssize_t n = ::read(timerfd, &howmany, sizeof(howmany));    std::cout << "TimerQueue::handleRead() " << howmany << " at " << now.toString() << std::endl;    if (n != sizeof howmany)    {std::cout << "TimerQueue::handleRead() reads " << n << " bytes instead of 8" << std::endl;    }}/* 重置 timerfd 的超時時間 */void resetTimerfd(int timerfd, Timestamp expiration){struct itimerspec newValue;    struct itimerspec oldValue;    bzero(&newValue, sizeof newValue);    bzero(&oldValue, sizeof oldValue);    newValue.it_value = howMuchTimeFromNow(expiration);    //到這個時間后,會產生一個定時事件    int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue);    if (ret)    {std::cout << "timerfd_settime()" << std::endl;    }}} // namespace detail} // namespace Tattoousing namespace Tattoo;using namespace Tattoo::detail;TimeHeap::TimeHeap(EventLoop *loop)    : loop_(loop),      timerfd_(createTimerfd()),      timerfdChannel_(loop, timerfd_),      timers_(){// 設置自己獨特的回調函數,并不是和普通的Channel 一樣,直接喚醒了對應的協程    timerfdChannel_.setHandleCallback(        std::bind(&TimeHeap::handleRead, this));    timerfdChannel_.enableReading();}TimeHeap::~TimeHeap(){timerfdChannel_.disableAll();    ::close(timerfd_);    for (auto it = timers_.begin();         it != timers_.end(); ++it)    {delete it->second;    }}/* 添加一個定時器 ,返回定時器指針,會在 channel->addEpoll 函數中使用到,因為要刪除對應的定時器*/Timer *TimeHeap::addTimer(Timestamp when){Timer *timer = new Timer(when);    如果當前插入的定時器 比隊列中的定時器都早 則返回真    bool earliestChanged = insert(timer);    //最早的超時時間改變了,就需要重置timerfd_的超時時間    if (earliestChanged)    {//timerfd_ 重新設置超時時間,使得 timerfd  的定時事件始終是最小的        resetTimerfd(timerfd_, timer->expiration());    }    return timer;}/* 刪除一個定時器 */void TimeHeap::delTimer(Timer *timer){auto it = timers_.find(timer->expire_);    if (it != timers_.end())    {timers_.erase(it);    }    return;}//timerfd 可讀 的回調void TimeHeap::handleRead(){Timestamp now(Timestamp::now());    //先讀取    readTimerfd(timerfd_, now);    std::vectorexpired = getExpired(now);    for (std::vector::iterator it = expired.begin();         it != expired.end(); ++it)    {it->second->run(); //run->Resume()    }    reset(expired, now); //這里主要是改變 timerfd 的定時最小值}//獲取所有超時的定時器std::vectorTimeHeap::getExpired(Timestamp now){std::vectorexpired;    auto it = timers_.lower_bound(now);    assert(it == timers_.end() || now < it->first);    std::copy(timers_.begin(), it, back_inserter(expired));    timers_.erase(timers_.begin(), it);    return expired;}void TimeHeap::reset(const std::vector&expired, Timestamp now){Timestamp nextExpire;    for (std::vector::const_iterator it = expired.begin();         it != expired.end(); ++it)    {delete it->second;    }    if (!timers_.empty()) //timers_ 不為空    {/*獲取當前定時器集合中的最早定時器的時間戳,作為下次超時時間*/        nextExpire = timers_.begin()->second->expiration();    }    //如果取得的時間 >0就改變 timerfd 的定時    if (nextExpire.valid())    {resetTimerfd(timerfd_, nextExpire);    }}bool TimeHeap::insert(Timer *timer){bool earliestChanged = false;    Timestamp when = timer->expiration();    auto it = timers_.begin();    if (it == timers_.end() || when < it->first)    {earliestChanged = true;    }    timers_.insert(std::make_pair(when, timer));    return earliestChanged;}

OK,上面的就是具體的實現代碼了,下面來說一下幾個點:

1.如何添加定時器?

在我寫的協程庫中是這樣實現的: Channel::addEpoll()->loop_->runAfter(10)->timerHeap_->addTimer()

2.如何刪除定時器?

loop_->cancel()->timerHeap_->delTimer()

3.如何將timerfd與Eventloop 統一起來?

首先來看一下eventloop:

.h

#include "Callbacks.h"#include "Timestamp.h"#include#include#include "routine.h"namespace Tattoo{class Channel;class Epoll;class TimeHeap;class Timer;class RoutineEnv_t;class EventLoop{public:    EventLoop();    ~EventLoop();    void loop();    // timers    Timer *runAt(const Timestamp &time);    Timer *runAfter(double delay);    void cancel(Timer *timer);    void updateChannel(Channel *channel);    void removeChannel(Channel *channel);  private:    typedef std::vectorChannelList;    Epoll *epoll_;    TimeHeap *timerHeap_;    ChannelList activeChannels_;    RoutineEnv_t *rouEnv_;};} // namespace Tattoo

.cpp

#include#include "Channel.h"#include "Epoll.h"#include "MiniHeap.h"#include "EventLoop.h"using namespace Tattoo;const int kPollTimeMs = 10000; // 10 sEventLoop::EventLoop()    : rouEnv_(get_curr_thread_env()), //  一個 eventloop  對應一個 Routine_env      epoll_(new Epoll(this)),      timerHeap_(new TimeHeap(this))       //在TimeHead初始化時,就會將 timerfd 加入 epoll 監聽中{// std::cout << "EventLoop created " << this << std::endl;    rouEnv_->envEventLoop_ = this; //關鍵點}EventLoop::~EventLoop(){}void EventLoop::loop(){while (1)    {activeChannels_.clear();        int ret = epoll_->poll(kPollTimeMs, &activeChannels_);        for (auto it = activeChannels_.begin();             it != activeChannels_.end(); ++it)        {(*it)->handleEvent(); //事件分發,記得注冊時間回調(一般就是 Resume())        }    }    std::cout << "EventLoop " << this << " stop looping" << std::endl;}Timer *EventLoop::runAt(const Timestamp &time){return timerHeap_->addTimer(time);}Timer *EventLoop::runAfter(double delay){Timestamp time(addTime(Timestamp::now(), delay));    runAt(time);}void EventLoop::cancel(Timer *timer){timerHeap_->delTimer(timer);}void EventLoop::updateChannel(Channel *channel){epoll_->updateChannel(channel);}void EventLoop::removeChannel(Channel *channel){epoll_->removeChannel(channel);}

4.定時器的組織方式(和 muduo 差不多,他用的是set,我用的是 multimap)

muduo定時器容器封裝了 Timer.h里面保存的是超時時間和回調函數, TimerQueue.h使用set容器保存多個定時器, 然后在TimerQueue中使用timerfd_create創建一個timerfd句柄, 插入定時器A后先比較A的觸發時間和TimerQueue的觸發時間, 如果A的觸發時間比其小就使用timerfd_settime重置TimerQueue的timerfd的觸發時間, TimerQueue中的timerfd的觸發時間永遠與保存的定時器中觸發時間最小的那個相同, 然后timerfd觸發可讀后, 遍歷保存的多個定時器, 看看有沒有同時到期的, 有執行回調函數

4.協程庫中定時器的使用(與 libco 基本一樣)

先行閱讀:https://blog.csdn.net/liushengxi_root/article/details/88421955 主要函數(addEpoll):

void Channel::addEpoll(){//這里就設置的回調函數和 timerfd 設置的回調函數不一樣哦    setHandleCallback(std::bind(&Channel::handleFun, this));    events_ |= kReadEvent;    events_ |= kWriteEvent;    update();    Timer *tmp = loop_->runAfter(10);    //退出當前協程    get_curr_routine()->Yield();    //刪除加入的 epoll 信息和對應定時器    loop_->removeChannel(this);    loop_->cancel(tmp);}

事件到來會喚醒對應的協程,時間超時時 也會喚醒對應的協程(不會讓其一直阻塞下去)

主事件循環還是看上面的鏈接即可!!

運行結果:

責任編輯:

標簽:

相關推薦:

精彩放送:

新聞聚焦
Top 一区二区三区电影_国产伦精品一区二区三区视频免费_亚洲欧美国产精品va在线观看_国产精品一二三四
久久久91精品国产一区二区三区| 国产性猛交xxxx免费看久久| 中日韩午夜理伦电影免费| 亚洲精品1234| 欧美成人中文字幕在线| 亚洲人久久久| 欧美激情精品久久久六区热门| 久久综合国产精品| 在线观看成人一级片| 国产精品xxxxx| 最新成人在线| 亚洲午夜国产成人av电影男同| 一区二区精品在线| 中文亚洲视频在线| 欲香欲色天天天综合和网| 国产欧美日韩精品a在线观看| 亚洲茄子视频| 欧美日韩专区| 国产精品白丝黑袜喷水久久久| 欧美调教vk| 欧美亚州韩日在线看免费版国语版| 夜夜夜久久久| 猫咪成人在线观看| 欧美日韩免费在线观看| 国产精品一区二区三区乱码| 黑人巨大精品欧美一区二区小视频| 伊人久久婷婷| 性做久久久久久久免费看| 欧美激情91| 一区二区亚洲欧洲国产日韩| 亚洲一区二区在线视频| 欧美成人精品一区二区| 国产精品永久免费观看| 一级日韩一区在线观看| 欧美日韩直播| 亚洲最新视频在线| 欧美精品三级日韩久久| 亚洲激情网站免费观看| 欧美国产日韩a欧美在线观看| 在线观看日韩www视频免费| 欧美中文在线观看国产| 国产性做久久久久久| 欧美中文字幕在线播放| 黄色成人在线网址| 免费日本视频一区| 亚洲精品一区二区在线| 欧美日韩情趣电影| 亚洲女性喷水在线观看一区| 国产欧美视频一区二区三区| 久久高清免费观看| 国自产拍偷拍福利精品免费一| 久久午夜精品| 亚洲大片免费看| 欧美日韩激情网| 亚洲免费视频成人| 亚洲国产成人在线| 国产精品乱子乱xxxx| 蜜桃av噜噜一区| 亚洲一区二区三区精品视频| 在线成人激情| 国产在线高清精品| 国产精品wwwwww| 欧美激情一区在线观看| 久久精品国产一区二区三区| 亚洲日本无吗高清不卡| 国产午夜精品视频| 国产精品国色综合久久| 欧美日产一区二区三区在线观看| 欧美在线观看视频| 亚洲综合好骚| 亚洲欧美日本国产专区一区| 99精品国产高清一区二区| 亚洲精品久久在线| 夜夜嗨av一区二区三区中文字幕 | 国产一级精品aaaaa看| 欧美日韩精品一区二区| 欧美日韩高清在线| 国产精品v欧美精品v日韩| 欧美三级在线播放| 国产精品另类一区| 国产欧美精品日韩| 韩国v欧美v日本v亚洲v| 精品动漫3d一区二区三区免费| 精品69视频一区二区三区| 精品不卡一区二区三区| 亚洲国产日韩综合一区| 最新国产拍偷乱拍精品| 亚洲一区免费网站| 麻豆精品一区二区综合av| 欧美成人一区在线| 久久久久亚洲综合| 国产精品视频网| 麻豆精品视频在线观看| 久久精品一本| 国产精品美腿一区在线看| 国产麻豆日韩| 亚洲一区二区精品视频| 欧美国产精品久久| 亚洲一区视频| 午夜精品视频网站| 伊人蜜桃色噜噜激情综合| 欧美人成在线| 一区二区动漫| 激情久久影院| 男女激情久久| 亚洲欧美精品在线| 国产女主播一区| 亚洲欧美另类在线观看| 亚洲国产精品视频| 在线观看一区二区视频| 久久人人97超碰人人澡爱香蕉| 亚洲精品乱码久久久久久黑人| av成人免费在线| 欧美日韩三级| 一区二区三区久久久| 欧美视频在线视频| 午夜在线播放视频欧美| 国产一区二区看久久| 久久久亚洲一区| 最近中文字幕日韩精品| 亚洲自拍三区| 欧美三级网址| 快播亚洲色图| 伊人久久久大香线蕉综合直播| 久久久久久综合| 在线亚洲欧美| 亚洲成在人线av| 欧美日韩精品一区二区在线播放| 亚洲午夜激情免费视频| 狠狠色狠狠色综合日日五| 欧美日韩国产二区| 久久人91精品久久久久久不卡| 99精品国产高清一区二区| 国产亚洲观看| 国产麻豆9l精品三级站| 欧美精品日韩| 久久亚洲电影| 浪潮色综合久久天堂| 欧美一级淫片播放口| 亚洲一区免费网站| 野花国产精品入口| 99国产精品久久久久久久久久 | 国产视频精品免费播放| 欧美调教vk| 欧美成人综合网站| 欧美精品www在线观看| 欧美激情第二页| 欧美久久九九| 欧美日韩日日骚| 国产精品xvideos88| 国产伦精品一区二区三区免费| 欧美激情小视频| 国产日韩综合| 亚洲激情国产精品| 99精品国产热久久91蜜凸| 一区二区三区黄色| 亚洲综合久久久久| 久久久av水蜜桃| 欧美日韩天天操| 国产亚洲人成网站在线观看| 亚洲国产精品一区二区三区| 日韩一级片网址| 久久精品国产77777蜜臀| 欧美gay视频激情| 国自产拍偷拍福利精品免费一| 中国日韩欧美久久久久久久久| 欧美在线播放一区| 国产精品v一区二区三区| 国产在线观看精品一区二区三区| 亚洲国产小视频| 欧美一区二区国产| 欧美午夜片欧美片在线观看| 久久久久9999亚洲精品| 久久久欧美精品| 国产综合久久| 久久久久久一区| 影音先锋在线一区| 久久阴道视频| 亚洲国产视频a| 欧美日韩国产美| 亚洲午夜精品国产| 国产日韩欧美制服另类| 久久精品视频免费播放| 黄色在线成人| 欧美国产日韩一区二区在线观看| 亚洲大胆人体视频| 欧美图区在线视频| 久久xxxx| a4yy欧美一区二区三区| 国产精品免费aⅴ片在线观看| 新67194成人永久网站| 国内精品视频666| 国产精品久久久久久久久免费樱桃| 国产精品国产三级国产专区53| 欧美大片91| 欧美日韩亚洲一区二| 欧美三级网页| 国产美女精品| 在线精品一区| 亚洲国产清纯|