定时器是组织大量定时任务的模块。 定时器是项目底层基础的一个模块,很多业务场景中都需要解决一个问题:延时处理某些任务 。 数据结构: 按照先后过期的任务进行排序。 红黑树:nginx、workflow。 最小堆:libevent(最小二叉堆)、libev(最小四叉堆)、libuv(最小四叉堆)、go(最小四叉堆)。任务比较多的时候,最小四叉堆比最小二叉堆性能高 5% 。 跳表:redis。  按照执行序进行组织    驱动方式:拿当前时间跟数据结构中的最小值进行比较,如果当前时间小于最小值,说明所有的任务都没有过期。 reactor 网络编程模型 → IO 多路复用 + 非阻塞 IO 。timerfd:内核提供的一种机制,把延时任务检测视为一个 IO 进行处理,那么就可以把 timerfd 交由 IO 多路复用进行管理 。usleep 可以用来模拟时间指针移动,配合时间轮进行工作。  数据结构 → 红黑树 → multimap(因为过期时间作为 key 会重复)/ set  C++ 14 及以上版本实现了等价 key 的概念:只要比较方式一样,就是等价的 key 。基类的引用也具备多态性 。 触发方式的使用: 使用 timerfd 进行触发。 使用 IO 多路复用的最后一个参数进行触发。  # include  <sys/epoll.h> # include  <sys/timerfd.h> # include  <time.h>  # include  <unistd.h>  # include  <functional> # include  <chrono> # include  <set> # include  <memory> # include  <iostream> using  namespace  std; struct  TimerNodeBase  { time_t expire; uint64_t  id;  
} ; struct  TimerNode  :  public  TimerNodeBase { using  Callback =  std:: function< void ( const  TimerNode & node) > ; Callback func; TimerNode ( int64_t  id,  time_t expire,  Callback func)  :  func ( func)  { this -> expire =  expire; this -> id =  id; } 
} ; 
bool  operator  <  ( const  TimerNodeBase & lhd,  const  TimerNodeBase & rhd)  { if  ( lhd. expire <  rhd. expire)  { return  true ; }  else  if  ( lhd. expire >  rhd. expire)  { return  false ; }  else  return  lhd. id <  rhd. id; 
} class  Timer  { 
public : static  inline  time_t GetTick ( )  { return  chrono:: duration_cast < chrono:: milliseconds> ( chrono:: steady_clock:: now ( ) . time_since_epoch ( ) ) . count ( ) ; } TimerNodeBase AddTimer ( int  msec,  TimerNode:: Callback func)  { time_t expire =  GetTick ( )  +  msec; if  ( timeouts. empty ( )  ||  expire <=  timeouts. crbegin ( ) -> expire)  { auto  pairs =  timeouts. emplace ( GenID ( ) ,  expire,  std:: move ( func) ) ; return  static_cast < TimerNodeBase> ( * pairs. first) ; } auto  ele =  timeouts. emplace_hint ( timeouts. crbegin ( ) . base ( ) ,  GenID ( ) ,  expire,  std:: move ( func) ) ; return  static_cast < TimerNodeBase> ( * ele) ; } void  DelTimer ( TimerNodeBase & node)  { auto  iter =  timeouts. find ( node) ; if  ( iter !=  timeouts. end ( ) ) timeouts. erase ( iter) ; } void  HandleTimer ( time_t now)  { auto  iter =  timeouts. begin ( ) ; while  ( iter !=  timeouts. end ( )  &&  iter-> expire <=  now)  { iter-> func ( * iter) ; iter =  timeouts. erase ( iter) ; } } public : virtual  void  UpdateTimerfd ( const  int  fd)  { struct  timespec  abstime; auto  iter =  timeouts. begin ( ) ; if  ( iter !=  timeouts. end ( ) )  { abstime. tv_sec =  iter-> expire /  1000 ; abstime. tv_nsec =  ( iter-> expire %  1000 )  *  1000000 ; }  else  { abstime. tv_sec =  0 ; abstime. tv_nsec =  0 ; } struct  itimerspec  its =  { . it_interval =  { } , . it_value =  abstime} ; timerfd_settime ( fd,  TFD_TIMER_ABSTIME,  & its,  nullptr ) ; } private : static  inline  uint64_t  GenID ( )  { return  gid++ ; } static  uint64_t  gid;  set< TimerNode,  std:: less< >>  timeouts; 
} ; 
uint64_t  Timer:: gid =  0 ; int  main ( )  { int  epfd =  epoll_create ( 1 ) ; int  timerfd =  timerfd_create ( CLOCK_MONOTONIC,  0 ) ; struct  epoll_event  ev =  { . events= EPOLLIN |  EPOLLET} ; epoll_ctl ( epfd,  EPOLL_CTL_ADD,  timerfd,  & ev) ; unique_ptr< Timer>  timer =  make_unique < Timer> ( ) ; int  i =  0 ; timer-> AddTimer ( 1000 ,  [ & ] ( const  TimerNode & node)  { cout <<  Timer :: GetTick ( )  <<  " node id:"  <<  node. id <<  " revoked times:"  <<  ++ i <<  endl; } ) ; timer-> AddTimer ( 1000 ,  [ & ] ( const  TimerNode & node)  { cout <<  Timer :: GetTick ( )  <<  " node id:"  <<  node. id <<  " revoked times:"  <<  ++ i <<  endl; } ) ; timer-> AddTimer ( 3000 ,  [ & ] ( const  TimerNode & node)  { cout <<  Timer :: GetTick ( )  <<  " node id:"  <<  node. id <<  " revoked times:"  <<  ++ i <<  endl; } ) ; auto  node =  timer-> AddTimer ( 2100 ,  [ & ] ( const  TimerNode & node)  { cout <<  Timer :: GetTick ( )  <<  " node id:"  <<  node. id <<  " revoked times:"  <<  ++ i <<  endl; } ) ; timer-> DelTimer ( node) ; cout <<  "now time:"  <<  Timer :: GetTick ( )  <<  endl; struct  epoll_event  evs[ 64 ]  =  { 0 } ; while  ( true )  { timer-> UpdateTimerfd ( timerfd) ; int  n =  epoll_wait ( epfd,  evs,  64 ,  - 1 ) ; time_t now =  Timer :: GetTick ( ) ; for  ( int  i =  0 ;  i <  n;  i++ )  { } timer-> HandleTimer ( now) ; } epoll_ctl ( epfd,  EPOLL_CTL_DEL,  timerfd,  & ev) ; close ( timerfd) ; close ( epfd) ; return  0 ; 
}