事件庫之Libev(一)

##使用Libev Libev的做者寫了一份很好的官方Manual,比較的齊全,即介紹了Libev的設計思想,也介紹了基本使用還包括內部各種事件詳細介紹。這裏略微贅述一下。Libev經過一個 ·struct ev_loop· 結結構表示一個事件驅動的框架。在這個框架裏面經過ev_xxx結構,ev_initev_xxx_setev_xxx_start接口箱這個事件驅動的框架裏面註冊事件監控器,當相應的事件監控器的事件出現時,便會觸發該事件監控器的處理邏輯,去處理該事件。處理完以後,這些監控器進入到下一輪的監控中。符合一個標準的事件驅動狀態的模型。框架

Libev 除了提供了基本的三大類事件(IO事件、定時器事件、信號事件)外還提供了週期事件、子進程事件、文件狀態改變事件等多個事件,這裏咱們用三大基本事件寫一個例子,和Manual上的相似,可是沒有作收尾工做,爲的是將事件的框架清晰的呈現出來。函數

#include<ev.h>
#include <stdio.h>
#include <signal.h>
#include <sys/unistd.h>

ev_io io_w;
ev_timer timer_w;
ev_signal signal_w;

void io_action(struct ev_loop *main_loop,ev_io *io_w,int e)
{
        int rst;
        char buf[1024] = {'\0'};
        puts("in io cb\n");
        read(STDIN_FILENO,buf,sizeof(buf));
        buf[1023] = '\0';
        printf("Read in a string %s \n",buf);
        ev_io_stop(main_loop,io_w);
       
}

void timer_action(struct ev_loop *main_loop,ev_timer *timer_w,int e)
{
        puts("in tiemr cb \n");
        ev_timer_stop(main_loop,timer_w);
        
}

void signal_action(struct ev_loop *main_loop,ev_signal signal_w,int e)
{
        puts("in signal cb \n");
        ev_signal_stop(main_loop,signal_w);
        ev_break(main_loop,EVBREAK_ALL);
}

int main(int argc ,char *argv[])
{
        struct ev_loop *main_loop = ev_default_loop(0);
        ev_init(&io_w,io_action);
        ev_io_set(&io_w,STDIN_FILENO,EV_READ);  
        ev_init(&timer_w,timer_action);
        ev_timer_set(&timer_w,2,0);       
        ev_init(&signal_w,signal_action);
        ev_signal_set(&signal_w,SIGINT); 

        ev_io_start(main_loop,&io_w);
        ev_timer_start(main_loop,&timer_w);
        ev_signal_start(main_loop,&signal_w);
        
        ev_run(main_loop,0);

return 0;
}

下面對使用到的這些API進行說明。oop

這裏使用了3種事件監控器,分別監控IO事件、定時器事件以及信號事件。所以定義了3個監控器(watcher),以及觸發監控器時要執行動做的回調函數。Libev定義了多種監控器,命名方式爲 ev_xxx 這裏xxx表明監控器類型,其實現是一個結構體,設計

typedef struct ev_io
{
  ....
} ev_io;

經過宏定義能夠簡寫爲 ev_xxx。回調函數的類型爲 void cb_name(struct ev_loop *main_loop,ev_xxx *io_w,int event)code

在main中,首先定義了一個事件驅動器的結構 struct ev_loop *main_loop 這裏調用 ev_default_loop(0) 生成一個預製的全局驅動器。這裏能夠參考Manual中的選擇。而後依次初始化各個監控器以及設置監控器的觸發條件。接口

初始化監控器的過程是將相應的回調函數即觸發時的動做註冊到監控器上。進程

設置觸發條件則是該條件產生時纔去執行註冊到監控器上的動做。對於IO事件,通常是設置特定fd上的的可讀或可寫事件,定時器則是多久後觸發。這裏定時器的觸發條件中還有第三參數,表示第一次觸發後,是否循環,若爲0則吧循環,不然按該值循環。信號觸發器則是設置觸發的信號。事件

在初始化並設置好觸發條件後,先調用ev_xxx_start 將監控器註冊到事件驅動器上。接着調用 ev_run 開始事件驅動器。get

在事件的觸發動做裏面。我加入了一個 ev_xxx_stop 函數,與上面對應,也就是講改監控器從事件驅動器裏面註銷掉。使其再也不起做用。而在信號觸發的動做中還加入了一個 ev_break 該函數可使進程跳出 main_loop 事件驅動器循環,也就是關閉事件驅動器。結束這一邏輯。回調函數

libev最簡單的示例就是這樣的一個結構。定義一個監控器、書寫觸發動做邏輯、初始化監控器、設置監控器觸發條件、將監控器加入大事件驅動器的循環中便可。一個比較清晰的事件驅動框架。

libev的事件驅動過程能夠想象成以下的僞代碼:

do_some_init()
is_run = True
while is_run:
    t = caculate_loop_time()
    deal_loop(t)
    deal_with_pending_event()
do_some_clear()

首先作一些初始化操做,而後進入到循環中,該循環經過一個狀態位來控制是否執行。在循環中,計算出下一次輪詢的時間,這裏輪詢的實現就採用了系統提供的epoll、kqueue等機制。再輪詢結束後檢查有哪些監控器的被觸發了,依次執行觸發動做。這裏不要糾結信號事件、定時器時間咋都通過了 deal_loop libev是如何實現的這裏暫且不討論,這個僞代碼只是大體表示下libev的總體框架。

相關文章
相關標籤/搜索