2013年10月29日 星期二

multi thread in libev

Libev 是一個事件的library(event loop library)
透過loop與monitor的方式來做事件的處理
觸發不同的事件來執行不同的 callback
Libev 官方網站

這算是我工作上第一個遇到的新工具~
一開始看官方文件 還是霧煞煞~
不過 實際去RUN個幾次 你就會懂他的 邏輯與方式了~

這次要回頭處理 原本的ev 事件程式
想測試看看用 multi thread 來提升 處理效能

使用libev 如果希望工頭(主程序)隨時身邊都有工人(thread)待命,一有事情就派工人處理
但要讓工人處於待命狀態,而且又要聽命於工頭
其中 ev_async 是很重要的一個"秘書",可以幫忙與其他工人溝通


  ev_async async_watcher;
  ev_loop thread_loop;
  ev_io main_event;
  EV_P;

  int main()
  {
    loop = ev_default_loop(0);
    thread_loop= ev_loop_new(0);

    pthread_t thread;

    ev_async_init(async_watcher, async_cb);
    ev_async_start(thread_loop ,async_watcher);

    pthread_create(&thread, NULL, pthread_function, NULL);

    ev_io_init(&main_event, cb_main_callback, fd, EV_READ);
    ev_run(EV_A_ 0);
  }

  void *pthread_function(void *ptr)
  {
    ev_run(thread_loop, 0);
    pthread_exit(0);
    return NULL;
  }

  void cb_main_callback(EV_P_ ev_io *w, int revents)
  {
    if(ev_async_pending(&mthread[thread_count].async_watcher) == 0)
    {
      async_watcher.data = (void *)"Test Multi Thread";
      ev_async_send(thread_loop , &async_watcher);
    }
  }

  void async_cb(EV_P_ ev_async *w, int revents)
  {
    char * msg;
    msg = (char *)w->data
    printf("%s\n",msg);
  }

擷取程式中 部分程式碼說明一下 ev_async的 運作流程
首先主程序 在執行 ev_run(EV_A_ 0); 之前
註冊了一個 async_watcher 並指定 callback async_cb()
並啟 ev_async_start(thread_loop ,async_watcher);
在pthread_create() 的時候讓 thread_loop 運作 此時因為
有註冊async_watcher  所以不會 thread_loop  直接結束掉

再來重點在於 主程序 進到 cb_main_callback() 中
ev_async_pending() 這個動作 要跟 ev_async_send()
一起講會比較清楚
在ev_async_send()在 thread_loop 做個標記 此時會可以讓loop
去進到async_cb() 而此時會把 ev_async_send()所做的標記重置
而 ev_async_pending() 到底有啥作用呢
有人可能從字面上覺得 是在看是否呈現等待狀態
但實際的運作是
當已經被ev_async_send()標記 但loop並未觸發,則會回傳非0的值
所以我們必須判斷 ev_async_pending()等於0
才能再進行一次 ev_async_send()

通常在使用會遇到一個問題 就是 我需要帶資料或變數改怎麼處理
可能比較常看到 是使用 全域的變數 使用 lock 的方式
而其實 ev 事件 的monitor的struct 都會有一些變數可以使用
可以很方便在不同的callback傳遞

  struct ev_async {
    sig_atomic_t volatile sent;
    int active;
    int pending;
    int priority;
    void* data;
    void (*cb)(struct ev_loop *loop, struct ev_async *w, int revents);
  };

更多範例 可以在搜尋關鍵字 "libev thread" , "ev_async"
下面連結是 網路上的範例 自己有稍微修改測試了一下~
example ev_thread.c 

參考連結

http://www.codeday.net/?p=68 (libev 一些struct 結構)
http://stackoverflow.com/questions/14621261/using-libev-with-multiple-threads