Libev——ev_timer 相對時間定時器


Libev中的超時監視器ev_timer,是簡單的相對時間定時器,它會在給定的時間點觸發超時事件,還可以在固定的時間間隔之后再次觸發超時事件。

1.超時監視器ev_timer結構

typedef struct ev_timer
{
   /*前五行為EV_WATCHER 參數具體含義在libev I/O事件中有描述*/
    int active; 
    int pending;
    int priority;
    void *data;
    void (*cb)(struct ev_loop *loop, struct ev_timer *w, int revents);  //回調函數
 
    ev_tstamp at; // 定時器第一次觸發的時間點,根據mn_now設置
    ev_tstamp repeat; //repeat 必須>=0,當大於0時表示每隔repeat秒該定時器再次觸發;0表示只觸發一次;double 型
} ev_timer;watcher_

at和repeat兩個成員為是ev_timer特有的

2.ev_watcher_timer

#define EV_WATCHER_TIME(type)			\ //定時器
  EV_WATCHER (type)				\
  ev_tstamp at;     // 定時器第一次觸發的時間點,根據mn_now設置

 ev_watcher_time的結構與ev_timer幾乎一樣,只是少了最后一個成員。該結構其實是ev_timer和ev_periodic的父類,它包含了ev_timer和ev_periodic的共有成員。

3.堆元素ANHE(這里使用小頂堆,即子節點均大於父節點,即堆頂元素所等待激活事件是最小的)

//----- 宏EV_HEAP_CACHE_AT是為了提高在堆中的緩存利用率,主要是為了對at進行緩
#if EV_HEAP_CACHE_AT
    typedef struct 
    {
        ev_tstamp at;
        WT w;
    } ANHE;//除了包含該指針WT之外,還緩存了 ev_watcher_time 中的成員 at,堆中元素就是根據 at 的值進行組織的,具有最小 at 值得節點就是根節點。
#else  
typedef WT ANHE;//是一個指向時間監視器結構 ev_watcher_time 的指針 WT
#endif

 宏EV_HEAP_CACHE_AT的作用,是為了提高在堆中的緩存利用率,如果沒有定義該宏,堆元素就是指向ev_watcher_time結構的指針。如果定義了該宏,則還將堆元素的關鍵成員at進行緩存。

4.定時器事件的初始化與設置

//初始化,意味着在after秒后執行,設置為0則會立即執行一次;然后每隔repeat秒執行一次
#define ev_timer_init(ev,cb,after,repeat)        

    do { ev_init ((ev), (cb)); ev_timer_set ((ev),(after),(repeat)); } while (0)

//設置
#define ev_timer_set(ev,after_,repeat_)   

   do { ((ev_watcher_time *)(ev))->at = (after_); (ev)->repeat = (repeat_); } while (0)

5.啟動定時器ev_timer_start 

void noinline
ev_timer_start (EV_P_ ev_timer *w) EV_THROW
{
  if (expect_false (ev_is_active (w)))
    return;

  ev_at (w) += mn_now;//首先設置監視器的at成員,表明在at時間點,超時事件會觸發,注意at是根據mn_now設置的,也就是相對於系統啟動時間而言的(或者是日歷時間)

  assert (("libev: ev_timer_start called with negative timer repeat value", w->repeat >= 0.));

  EV_FREQUENT_CHECK;

  //定時器數量 有多少個定時器
  ++timercnt;
  //事件激活相關 其中active即為timercnt(timers下標)
  ev_start (EV_A_ (W)w, timercnt + HEAP0 - 1);
 // 調整timers內存的大小 array_needsize (ANHE, timers, timermax, ev_active (w)
+ 1, EMPTY2); ANHE_w (timers [ev_active (w)]) = (WT)w; ANHE_at_cache (timers [ev_active (w)]);//從watcher中獲取at值 //因為新添加的元素放在數組后面,然后向上調整堆 upheap (timers, ev_active (w)); EV_FREQUENT_CHECK; /*assert (("libev: internal timer heap corruption", timers [ev_active (w)] == (WT)w));*/ }

當對某一節點執行 upheap() 時,就是與其父節點進行比較,如果其值比父節點小,則交換,然后在對這個父節點重復 upheap() ,直到頂層或其值大於父節點的值。

inline_speed void
ev_start (EV_P_ W w, int active)
{
  pri_adjust (EV_A_ w);//調整優先級
  w->active = active;//監視器的active成員,表明該監視器在堆數組中的下標
  ev_ref (EV_A);
}

6 timers_reify

每次調用backend_poll之前,都會根據ANHE_at (timers [HEAP0]) - mn_now的值,校准backend_poll的阻塞時間waittime,這樣就能盡可能的保證定時器能夠按時觸發。

調用backend_poll之后,就會調用timers_reify查看timers中哪些定時器觸發了,獲得所有超時的timer,代碼如下:

/* make timers pending 掛起狀態*/
inline_size void
timers_reify (EV_P)
{
  EV_FREQUENT_CHECK;

  if (timercnt && ANHE_at (timers [HEAP0]) < mn_now)//定時器值不為0,且堆頂值小於mn_now(相對於系統啟動時間)
    {
      //timercnt 為定時器的值,在timer_start中累加
      do
        {
          ev_timer *w = (ev_timer *)ANHE_w (timers [HEAP0]);

          /*assert (("libev: inactive timer on timer heap detected", ev_is_active (w)));*/

          /* first reschedule or stop timer */
          
          if (w->repeat)//若為重復定時器,一次性定時器w->repeat=0
            {
              ev_at (w) += w->repeat;//啟動時間加重復時間
              if (ev_at (w) < mn_now)//還小於當前時間
                ev_at (w) = mn_now;//賦值當前時間

              assert (("libev: negative ev_timer repeat value found while processing timers", w->repeat > 0.));

              ANHE_at_cache (timers [HEAP0]);//  #define ANHE_at_cache(he) (he).at = (he).w->at /* update at from watcher */
             //向下調整堆,定時器仍然存在該數組中
              downheap (timers, timercnt, HEAP0);
            }
          else
            ev_timer_stop (EV_A_ w); /* nonrepeating: stop timer 一次性定時器 停止 */

          EV_FREQUENT_CHECK;
          //將超時的事件加入rfeeds[]結構中
          feed_reverse (EV_A_ (W)w);
        }
      while (timercnt && ANHE_at (timers [HEAP0]) < mn_now);//定時器不為0且堆頂的值一直小於當前時間就重復上述操作

      feed_reverse_done (EV_A_ EV_TIMER);//將rfeeds[]結構中的watcher插入到pengdings數組的操作
    }
}
6 停止定時器ev_stop_timer
void noinline
ev_timer_stop (EV_P_ ev_timer *w) EV_THROW
{

    //清除pendings[]激活事件隊列中,關於w的事件
  clear_pending (EV_A_ (W)w);
  if (expect_false (!ev_is_active (w)))
    return;

  EV_FREQUENT_CHECK;

  {
    int active = ev_active (w);//這個地方還不是很理解

    assert (("libev: internal timer heap corruption", ANHE_w (timers [active]) == (WT)w));
    //定時器數量減1
    --timercnt;

    if (expect_true (active < timercnt + HEAP0))
      {

        //timers [active]中的元素用數組最后一個元素替換,最后一個元素正常情況下為最大值
        timers [active] = timers [timercnt + HEAP0];

        //比較下標為active處的元素與其父節點的元素,來決定采用向上、向下調整
        adjustheap (timers, timercnt, active);
      }
  }

  ev_at (w) -= mn_now;

  ev_stop (EV_A_ (W)w);

  EV_FREQUENT_CHECK;
}

  首先調用clear_pending,如果該監視器已經處於pending狀態,將其從pendings中刪除。然后根據監視器中的active成員,得到其在timers堆上的索引,將該監視器從堆timers上刪除,重新調整堆結構。然后調用ev_stop停止該監視器。

用圖來示意一下

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM