亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Libevent(2)— event、event_base

系統(tǒng) 2646 0

轉(zhuǎn)自:http://name5566.com/4198.html

?

參考文獻(xiàn)列表:
http://www.wangafu.net/~nickm/libevent-book/

此文編寫的時(shí)候,使用到的 Libevent 為 2.0.21。本文略過了關(guān)于 event 優(yōu)先權(quán)和超時(shí)相關(guān)的討論。

創(chuàng)建和銷毀 event_base

event_base 是首先需要被創(chuàng)建出來的對(duì)象。event_base 結(jié)構(gòu)持有了一個(gè) event 集合。如果 event_base 被設(shè)置了使用鎖,那么它在多個(gè)線程中可以安全的訪問。但是對(duì) event_base 的循環(huán)(下面會(huì)馬上解釋什么是“對(duì) event_base 的循環(huán)”)只能在某個(gè)線程中執(zhí)行。如果你希望多個(gè)線程進(jìn)行循環(huán),那么應(yīng)該做的就是為每一個(gè)線程創(chuàng)建一個(gè) event_base。

event_base 存在多個(gè)后端可以選擇(我們也把 event_base 后端叫做 event_base 的方法):

  1. select
  2. poll
  3. epoll
  4. kqueue
  5. devpoll
  6. evport
  7. win32

在我們創(chuàng)建 event_base 的時(shí)候,Libevent 會(huì)為我們選擇最快的后端。創(chuàng)建 event_base 通過函數(shù) event_base_new() 來完成:

  1. // 創(chuàng)建成功返回一個(gè)擁有默認(rèn)設(shè)置的 event base
  2. // 創(chuàng)建失敗返回 NULL
  3. struct event_base * event_base_new ( void );
  4. ?
  5. // 查看 event_base 實(shí)際上使用到的后端
  6. const char * event_base_get_method ( const struct event_base * base );

對(duì)于大多數(shù)程序來說,默認(rèn)設(shè)置已經(jīng)夠用了。

event_base 的釋放使用函數(shù):

  1. void event_base_free ( struct event_base * base );

事件循環(huán)(event loop)

event_base 會(huì)持有一組 event(這是我們前面說到的),換而言之就是說,我們可以向 event_base 中注冊(cè) event(具體如何注冊(cè)本文先不談)。如果我們向 event_base 中注冊(cè)了一些 event,那么就可以讓 Libevent 開始事件循環(huán)了:

  1. // 指定一個(gè) event_base 并開始事件循環(huán)
  2. // 此函數(shù)內(nèi)部被實(shí)現(xiàn)為一個(gè)不斷進(jìn)行的循環(huán)
  3. // 此函數(shù)返回 0 表示成功退出
  4. // 此函數(shù)返回 -1 表示存在未處理的錯(cuò)誤
  5. int event_base_dispatch ( struct event_base * base );

默認(rèn)的事件循環(huán)會(huì)在以下的情況停止(也就是 event_base_dispatch 會(huì)返回):

  1. 如果 base 中沒有 event,那么事件循環(huán)將停止
  2. 調(diào)用 event_base_loopbreak(),那么事件循環(huán)將停止
  3. 調(diào)用 event_base_loopexit(),那么事件循環(huán)將停止
  4. 如果出現(xiàn)錯(cuò)誤,那么事件循環(huán)將停止

事件循環(huán)會(huì)檢測(cè)是否存在活躍事件(之前已經(jīng)介紹過活躍事件這一術(shù)語: http://name5566.com/4190.html ),若存在活躍事件,那么調(diào)用事件對(duì)應(yīng)的回調(diào)函數(shù)。

停止事件循環(huán)的可以通過移除 event_base 中的 event 來實(shí)現(xiàn)。如果你希望在 event_base 中存在 event 的情況下停止事件循環(huán),可以通過以下函數(shù)完成:

  1. // 這兩個(gè)函數(shù)成功返回 0 失敗返回 -1
  2. // 指定在 tv 時(shí)間后停止事件循環(huán)
  3. // 如果 tv == NULL 那么將無延時(shí)的停止事件循環(huán)
  4. int event_base_loopexit ( struct event_base * base ,
  5. const struct timeval * tv );
  6. // 立即停止事件循環(huán)(而不是無延時(shí)的停止)
  7. int event_base_loopbreak ( struct event_base * base );

這里需要區(qū)別一下 event_base_loopexit(base, NULL) 和 event_base_loopbreak(base):

  1. event_base_loopexit(base, NULL) 如果當(dāng)前正在為多個(gè)活躍事件調(diào)用回調(diào)函數(shù),那么不會(huì)立即退出,而是等到所有的活躍事件的回調(diào)函數(shù)都執(zhí)行完成后才退出事件循環(huán)
  2. event_base_loopbreak(base) 如果當(dāng)前正在為多個(gè)活躍事件調(diào)用回調(diào)函數(shù),那么當(dāng)前正在調(diào)用的回調(diào)函數(shù)會(huì)被執(zhí)行,然后馬上退出事件循環(huán),而并不處理其他的活躍事件了

有時(shí)候,我們需要在事件的回調(diào)函數(shù)中獲取當(dāng)前的時(shí)間,這時(shí)候你不需要調(diào)用 gettimeofday() 而是使用 event_base_gettimeofday_cached()(你的系統(tǒng)可能實(shí)現(xiàn) gettimeofday() 為一個(gè)系統(tǒng)調(diào)用,你可以避免系統(tǒng)調(diào)用的開銷):

  1. // 獲取到的時(shí)間為開始執(zhí)行此輪事件回調(diào)函數(shù)的時(shí)間
  2. // 成功返回 0 失敗返回負(fù)數(shù)
  3. int event_base_gettimeofday_cached ( struct event_base * base ,
  4. struct timeval * tv_out );

如果我們需要(為了調(diào)試)獲取被注冊(cè)到 event_base 的所有的 event 和它們的狀態(tài),調(diào)用 event_base_dump_events() 函數(shù):

  1. // f 表示輸出內(nèi)容的目標(biāo)文件
  2. void event_base_dump_events ( struct event_base * base , FILE * f );

event

現(xiàn)在開始詳細(xì)的討論一下 event。在 Libevent 中 event 表示了一組條件,例如:

  1. 一個(gè)文件描述符可讀或者可寫
  2. 超時(shí)
  3. 出現(xiàn)一個(gè)信號(hào)
  4. 用戶觸發(fā)了一個(gè)事件

event 的相關(guān)術(shù)語:

  1. 一個(gè) event 通過 event_new() 創(chuàng)建出來,那么它是已初始化的,另外 event_assign() 也被用來初始化 event(但是有它特定的用法)
  2. 一個(gè) event 被注冊(cè)到(通過 add 函數(shù)添加到)一個(gè) event_base 中,其為 pending 狀態(tài)
  3. 如果 pending event 表示的條件被觸發(fā)了,那么此 event 會(huì)變?yōu)榛钴S的,其為 active 狀態(tài),則 event 相關(guān)的回調(diào)函數(shù)被調(diào)用
  4. event 可以是 persistent(持久的)也可以是非 persistent 的。event 相關(guān)的回調(diào)函數(shù)被調(diào)用之后,只有 persistent event 會(huì)繼續(xù)轉(zhuǎn)為 pending 狀態(tài)。對(duì)于非 persistent 的 event 你可以在 event 相關(guān)的事件回調(diào)函數(shù)中調(diào)用 event_add() 使得此 event 轉(zhuǎn)為 pending 狀態(tài)

event 常用 API:

  1. // 定義了各種條件
  2. // 超時(shí)
  3. #define EV_TIMEOUT 0x01
  4. // event 相關(guān)的文件描述符可以讀了
  5. #define EV_READ 0x02
  6. // event 相關(guān)的文件描述符可以寫了
  7. #define EV_WRITE 0x04
  8. // 被用于信號(hào)檢測(cè)(詳見下文)
  9. #define EV_SIGNAL 0x08
  10. // 用于指定 event 為 persistent
  11. #define EV_PERSIST 0x10
  12. // 用于指定 event 會(huì)被邊緣觸發(fā)(Edge-triggered 可參考 http://name5566.com/3818.html
  13. #define EV_ET 0x20
  14. ?
  15. // event 的回調(diào)函數(shù)
  16. // 參數(shù) evutil_socket_t --- event 關(guān)聯(lián)的文件描述符
  17. // 參數(shù) short --- 當(dāng)前發(fā)生的條件(也就是上面定義的條件)
  18. // 參數(shù) void* --- 其為 event_new 函數(shù)中的 arg 參數(shù)
  19. typedef void (* event_callback_fn )( evutil_socket_t , short , void *);
  20. ?
  21. // 創(chuàng)建 event
  22. // base --- 使用此 event 的 event_base
  23. // what --- 指定 event 關(guān)心的各種條件(也就是上面定義的條件)
  24. // fd --- 文件描述符
  25. // cb --- event 相關(guān)的回調(diào)函數(shù)
  26. // arg --- 用戶自定義數(shù)據(jù)
  27. // 函數(shù)執(zhí)行失敗返回 NULL
  28. struct event * event_new ( struct event_base * base , evutil_socket_t fd ,
  29. short what , event_callback_fn cb ,
  30. void * arg );
  31. ?
  32. // 釋放 event(真正釋放內(nèi)存,對(duì)應(yīng) event_new 使用)
  33. // 可以用來釋放由 event_new 分配的 event
  34. // 若 event 處于 pending 或者 active 狀態(tài)釋放也不會(huì)存在問題
  35. void event_free ( struct event * event );
  36. ?
  37. // 清理 event(并不是真正釋放內(nèi)存)
  38. // 可用于已經(jīng)初始化的、pending、active 的 event
  39. // 此函數(shù)會(huì)將 event 轉(zhuǎn)換為非 pending、非 active 狀態(tài)的
  40. // 函數(shù)返回 0 表示成功 -1 表示失敗
  41. int event_del ( struct event * event );
  42. ?
  43. // 用于向 event_base 中注冊(cè) event
  44. // tv 用于指定超時(shí)時(shí)間,為 NULL 表示無超時(shí)時(shí)間
  45. // 函數(shù)返回 0 表示成功 -1 表示失敗
  46. int event_add ( struct event * ev , const struct timeval * tv );

一個(gè)范例:

  1. #include <event2/event.h>
  2. ?
  3. // event 的回調(diào)函數(shù)
  4. void cb_func ( evutil_socket_t fd , short what , void * arg )
  5. {
  6. const char * data = arg ;
  7. printf ( "Got an event on socket %d:%s%s%s%s [%s]" ,
  8. ( int ) fd ,
  9. ( what & EV_TIMEOUT ) ? " timeout" : "" ,
  10. ( what & EV_READ ) ? " read" : "" ,
  11. ( what & EV_WRITE ) ? " write" : "" ,
  12. ( what & EV_SIGNAL ) ? " signal" : "" ,
  13. data );
  14. }
  15. ?
  16. void main_loop ( evutil_socket_t fd1 , evutil_socket_t fd2 )
  17. {
  18. struct event * ev1 , * ev2 ;
  19. struct timeval five_seconds = { 5 , 0 };
  20. // 創(chuàng)建 event_base
  21. struct event_base * base = event_base_new ();
  22. ?
  23. // 這里假定 fd1、fd2 已經(jīng)被設(shè)置好了(它們都被設(shè)置為非阻塞的)
  24. ?
  25. // 創(chuàng)建 event
  26. ev1 = event_new ( base , fd1 , EV_TIMEOUT | EV_READ | EV_PERSIST , cb_func ,
  27. ( char *) "Reading event" );
  28. ev2 = event_new ( base , fd2 , EV_WRITE | EV_PERSIST , cb_func ,
  29. ( char *) "Writing event" );
  30. ?
  31. // 注冊(cè) event 到 event_base
  32. event_add ( ev1 , & five_seconds );
  33. event_add ( ev2 , NULL );
  34. // 開始事件循環(huán)
  35. event_base_dispatch ( base );
  36. }

Libevent 能夠處理信號(hào)。信號(hào) event 相關(guān)的函數(shù):

  1. // base --- event_base
  2. // signum --- 信號(hào),例如 SIGHUP
  3. // callback --- 信號(hào)出現(xiàn)時(shí)調(diào)用的回調(diào)函數(shù)
  4. // arg --- 用戶自定義數(shù)據(jù)
  5. #define evsignal_new ( base , signum , callback , arg ) \
  6. event_new ( base , signum , EV_SIGNAL | EV_PERSIST , cb , arg )
  7. ?
  8. // 將信號(hào) event 注冊(cè)到 event_base
  9. #define evsignal_add ( ev , tv ) \
  10. event_add (( ev ),( tv ))
  11. ?
  12. // 清理信號(hào) event
  13. #define evsignal_del ( ev ) \
  14. event_del ( ev )

在通常的 POSIX 信號(hào)處理函數(shù)中,不少函數(shù)是不能被調(diào)用的(例如,不可重入的函數(shù)),但是在 Libevent 中卻沒有這些限制,因?yàn)樾盘?hào) event 設(shè)定的回調(diào)函數(shù)運(yùn)行在事件循環(huán)中。另外需要注意的是,在同一個(gè)進(jìn)程中 Libevent 只能允許一個(gè) event_base 監(jiān)聽信號(hào)。

性能相關(guān)問題

Libevent 提供了我們機(jī)制來重用 event 用以避免 event 在堆上的頻繁分配和釋放。相關(guān)的接口:

  1. // 此函數(shù)用于初始化 event(包括可以初始化棧上和靜態(tài)存儲(chǔ)區(qū)中的 event)
  2. // event_assign() 和 event_new() 除了 event 參數(shù)之外,使用了一樣的參數(shù)
  3. // event 參數(shù)用于指定一個(gè)未初始化的且需要初始化的 event
  4. // 函數(shù)成功返回 0 失敗返回 -1
  5. int event_assign ( struct event * event , struct event_base * base ,
  6. evutil_socket_t fd , short what ,
  7. void (* callback )( evutil_socket_t , short , void *), void * arg );
  8. ?
  9. // 類似上面的函數(shù),此函數(shù)被信號(hào) event 使用
  10. #define evsignal_assign ( event , base , signum , callback , arg ) \
  11. event_assign ( event , base , signum , EV_SIGNAL | EV_PERSIST , callback , arg )

已經(jīng)初始化或者處于 pending 的 event,首先需要調(diào)用 event_del() 后再調(diào)用 event_assign()。

這里我們進(jìn)一步認(rèn)識(shí)一下 event_new()、event_assign()、event_free()、event_del()
event_new() 實(shí)際上完成了兩件事情:

  1. 通過內(nèi)存分配函數(shù)在堆上分配了 event
  2. 使用 event_assign() 初始化了此 event

event_free() 實(shí)際上完成了兩件事情:

    1. 調(diào)用 event_del() 進(jìn)行 event 的清理工作
    2. 通過內(nèi)存分配函數(shù)在堆上釋放此 event

Libevent(2)— event、event_base


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 日日插夜夜操 | 久久久久国产一级毛片高清版 | 黄色片网站在线 | 五月天婷婷激情 | 国产欧美一区二区三区免费 | 一区二区三区四区视频在线观看 | 日日碰日日摸日日澡视频播放 | 国产成人在线小视频 | 天天伊人 | 一级毛片免费一级直接观看 | 青青青青啪视频在线观看 | 欧美精品专区免费观看 | 五月情视频在线观看 | 在线观看不卡视频 | 精品一区二区三区 不卡高清 | 国产成人精品日本亚洲语言 | 亚洲第九十七页 | 久久久久毛片免费观看 | 国内精品日本久久久久影院 | 亚洲福利一区二区三区 | 欧美激情一区二区三区视频 | 拔插拔插成人 | 97在线观看播放 | 2021国产成人综合亚洲精品 | 中文字幕精品在线视频 | 欧美日韩顶级毛片www免费看 | 99久久综合精品国产 | 日本成片网 | 久久99热这里只有精品7 | 91好色视频| 久久精品蜜芽亚洲国产a | 国产91在线 | 欧美 | 精品国产品香蕉在线观看75 | 自拍亚洲午夜伦li片影院 | 在线观看国产一区二区三区 | 啪啪网站色大全免费 | 最新69成人精品毛片 | 国产精品福利视频免费观看 | www一级片| 欧美国产精品一区二区免费 | 国产无套免费网站 |