日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

nginx的定时器

發布時間:2024/2/28 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 nginx的定时器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在nginx中有兩種事件類型,其中一種的引發點是epoll,也就是通過epoll來獲取事件的源頭,另外一種就是定時時間。。在前面的代碼中就已經遇到過了,例如當nginx獲取到一個客戶端的連接時,需要對該連接進行初始化,同時還要給這個連接增加一個定時器,如果都超時了請求的數據都還沒有接收完整,那么就直接斷開這個連接。。。


這里,nginx中的定時功能并沒有采用操作系統提供的定時器,而是自己實現了一個模擬定時器的方法。。。最核心的就是一顆紅黑樹。。。。


在Ngx_times.c文件中定義了很多關于時間的全局變量,其中對于定時時間最為重要的是:

[cpp]?view plaincopy
  • volatile?ngx_msec_t??????ngx_current_msec;??
  • ngx_msec_t為一個無符號的整形,用于代表當前的UTC時間,單位是毫秒。。

    我們首先來看添加定時事件的函數吧:

    [cpp]?view plaincopy
  • //將一個事件加入到紅黑樹當中,它的超時未timer時間??
  • static?ngx_inline?void??
  • ngx_event_add_timer(ngx_event_t?*ev,?ngx_msec_t?timer)???//timer說白了就是一個int的值,表示超時的事件,用于表示紅黑樹節點的key??
  • {??
  • ????ngx_msec_t??????key;??
  • ????ngx_msec_int_t??diff;??
  • ??
  • ????key?=?ngx_current_msec?+?timer;??//表示該event的超時時間,為當前時間的值加上超時變量??
  • ??
  • ????if?(ev->timer_set)?{??
  • ??
  • ????????/*?
  • ?????????*?Use?a?previous?timer?value?if?difference?between?it?and?a?new?
  • ?????????*?value?is?less?than?NGX_TIMER_LAZY_DELAY?milliseconds:?this?allows?
  • ?????????*?to?minimize?the?rbtree?operations?for?fast?connections.?
  • ?????????*/??
  • ??
  • ????????diff?=?(ngx_msec_int_t)?(key?-?ev->timer.key);??
  • ??
  • ????????if?(ngx_abs(diff)?<?NGX_TIMER_LAZY_DELAY)?{??
  • ????????????ngx_log_debug3(NGX_LOG_DEBUG_EVENT,?ev->log,?0,??
  • ???????????????????????????"event?timer:?%d,?old:?%M,?new:?%M",??
  • ????????????????????????????ngx_event_ident(ev->data),?ev->timer.key,?key);??
  • ????????????return;??
  • ????????}??
  • ??
  • ????????ngx_del_timer(ev);??
  • ????}??
  • ??
  • ????ev->timer.key?=?key;??
  • ??
  • ????ngx_log_debug3(NGX_LOG_DEBUG_EVENT,?ev->log,?0,??
  • ???????????????????"event?timer?add:?%d:?%M:%M",??
  • ????????????????????ngx_event_ident(ev->data),?timer,?ev->timer.key);??
  • ??
  • ????ngx_mutex_lock(ngx_event_timer_mutex);??
  • ??
  • ????ngx_rbtree_insert(&ngx_event_timer_rbtree,?&ev->timer);????//事件的timer域插入到紅黑樹當中??
  • ??
  • ????ngx_mutex_unlock(ngx_event_timer_mutex);??
  • ??
  • ????ev->timer_set?=?1;??
  • }??
  • 代碼其實還是比較的簡單,核心就是將當前event的timer插入到事件紅黑樹當中,其超時時間為當前的時間加上傳進來的超時時間。。。

    我們接著來看ngx_process_events_and_timers函數,

    [html]?view plaincopy
  • timer?=?ngx_event_find_timer();???
  • 這里用于獲取當前事件紅黑樹中最小的超時時間(也就是紅黑樹中最左邊的節點),將其提供給epoll,讓epoll的wait在這個時間內喚醒。。。

    接下來再來看ngx_epoll_process_events函數,

    [html]?view plaincopy
  • events?=?epoll_wait(ep,?event_list,?(int)?nevents,?timer);????//這個超時事件是從紅黑樹里面獲取的,當前最近的超時,這樣可以保證epoll的wait能夠在合適的時間內返回,保證定義的超時事件可以執行??
  • ??
  • ?err?=?(events?==?-1)???ngx_errno?:?0;??
  • ??
  • ?if?(flags?&?NGX_UPDATE_TIME?||?ngx_event_timer_alarm)?{??
  • ?????ngx_time_update();??
  • ?}??
  • ??
  • ?if?(err??
  • 每一次wait之后就會調用ngx_time_updateh函數來更新當前的與時間相關的全局變量。。。

    接下來回到ngx_process_event_and_timers中,

    [html]?view plaincopy
  • if?(delta)?{??
  • ????ngx_event_expire_timers();??
  • }??
  • 這部分代碼用于處理所有的超時時間。。來看看它的代碼吧: [cpp]?view plaincopy
  • //處理紅黑樹中所有超時的事件??
  • void??
  • ngx_event_expire_timers(void)??
  • {??
  • ????ngx_event_t????????*ev;??
  • ????ngx_rbtree_node_t??*node,?*root,?*sentinel;??
  • ??
  • ????sentinel?=?ngx_event_timer_rbtree.sentinel;??
  • ??
  • //死循環,找到所有的超時的timer,然后處理他們??
  • ????for?(?;;?)?{??
  • ??
  • ????????ngx_mutex_lock(ngx_event_timer_mutex);??
  • ??
  • ????????root?=?ngx_event_timer_rbtree.root;??
  • ??
  • ????????if?(root?==?sentinel)?{??
  • ????????????return;??
  • ????????}??
  • ??
  • ????????node?=?ngx_rbtree_min(root,?sentinel);???//獲取key最小的節點??
  • ??
  • ????????/*?node->key?<=?ngx_current_time?*/??
  • ??
  • ????????if?((ngx_msec_int_t)?(node->key?-?ngx_current_msec)?<=?0)?{???//判斷該節點是否超時,如果超時的話,就執行處理函數,否則就可以跳出循環了??
  • ????????????//通過偏移來獲取當前timer所在的event??
  • ????????????ev?=?(ngx_event_t?*)?((char?*)?node?-?offsetof(ngx_event_t,?timer));??
  • ??
  • #if?(NGX_THREADS)??
  • ??
  • ????????????if?(ngx_threaded?&&?ngx_trylock(ev->lock)?==?0)?{??
  • ??
  • ????????????????/*?
  • ?????????????????*?We?cannot?change?the?timer?of?the?event?that?is?being?
  • ?????????????????*?handled?by?another?thread.??And?we?cannot?easy?walk?
  • ?????????????????*?the?rbtree?to?find?next?expired?timer?so?we?exit?the?loop.?
  • ?????????????????*?However,?it?should?be?a?rare?case?when?the?event?that?is?
  • ?????????????????*?being?handled?has?an?expired?timer.?
  • ?????????????????*/??
  • ??
  • ????????????????ngx_log_debug1(NGX_LOG_DEBUG_EVENT,?ev->log,?0,??
  • ???????????????????????????????"event?%p?is?busy?in?expire?timers",?ev);??
  • ????????????????break;??
  • ????????????}??
  • #endif??
  • ??
  • ????????????ngx_log_debug2(NGX_LOG_DEBUG_EVENT,?ev->log,?0,??
  • ???????????????????????????"event?timer?del:?%d:?%M",??
  • ???????????????????????????ngx_event_ident(ev->data),?ev->timer.key);??
  • //將當前timer移除??
  • ????????????ngx_rbtree_delete(&ngx_event_timer_rbtree,?&ev->timer);??
  • ??
  • ????????????ngx_mutex_unlock(ngx_event_timer_mutex);??
  • ??
  • #if?(NGX_DEBUG)??
  • ????????????ev->timer.left?=?NULL;??
  • ????????????ev->timer.right?=?NULL;??
  • ????????????ev->timer.parent?=?NULL;??
  • #endif??
  • ??
  • ????????????ev->timer_set?=?0;??
  • ??
  • #if?(NGX_THREADS)??
  • ????????????if?(ngx_threaded)?{??
  • ????????????????ev->posted_timedout?=?1;??
  • ??
  • ????????????????ngx_post_event(ev,?&ngx_posted_events);??
  • ??
  • ????????????????ngx_unlock(ev->lock);??
  • ??
  • ????????????????continue;??
  • ????????????}??
  • #endif??
  • ??
  • ????????????ev->timedout?=?1;??
  • ??
  • ????????????ev->handler(ev);???//調用event的handler來處理這個事件??
  • ??
  • ????????????continue;??
  • ????????}??
  • ??
  • ????????break;??
  • ????}??
  • ??
  • ????ngx_mutex_unlock(ngx_event_timer_mutex);??
  • }??
  • 其實還是很簡單的,說白了就是不斷的從紅黑樹中獲取key值最小的節點,然后判斷它是否已經超時,如果超時的話就將其從紅黑樹中刪除,然后調用處理函數。。。


    這樣子nginx的定時時間處理也就ok了。。。。

    總結

    以上是生活随笔為你收集整理的nginx的定时器的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。