2011-10-04 184 views
8

我目前正在使用libevent編寫一個多線程應用程序。libevent中的用戶觸發事件

有些事件是由IO觸發的,但我需要通過使用event_active()由代碼本身在線程間觸發的一對事件。

我試圖寫一個簡單的程序,其中顯示出我的問題是:)

事件使用創建event_new(和FD設置爲-1。

當調用event_add()時,如果使用超時結構,事件稍後將由event_base_dispatch正確處理。

如果event_add(EV,NULL)被替代地使用,則返回0(明顯成功的),但event_base_dispatch()返回1(這意味着沒有事件沒有被正確註冊。)

此行爲可以被測試使用下面的代碼和交換的event_add線:

#include <event2/event.h> 
#include <unistd.h> 

void cb_func (evutil_socket_t fd, short flags, void * _param) { 
    puts("Callback function called!"); 
} 

void run_base_with_ticks(struct event_base *base) 
{ 
    struct timeval one_sec; 

    one_sec.tv_sec = 1; 
    one_sec.tv_usec = 0; 
    struct event * ev1; 
    ev1 = event_new(base, -1, EV_PERSIST, cb_func, NULL); 
    //int result = event_add(ev1, NULL); 
    int result = event_add(ev1, &one_sec); 
    printf("event_add result: %d\n",result); 

    while (1) { 
    result = event_base_dispatch(base); 
    if (result == 1) { 
     printf("Failed: event considered as not pending dispite successful event_add\n"); 
     sleep(1); 
    } else { 
     puts("Tick"); 
    } 
    } 
} 

int main() { 
    struct event_base *base = event_base_new(); 
    run_base_with_ticks(base); 
    return 0; 
} 

編譯:G ++ sample.cc -levent

的事情是,我不需要超時,並且不希望使用正年超時作爲解決方法。所以如果這不是使用用戶觸發事件的正確方法,我想知道它是如何完成的。

回答

8

你的方法是合理的。在Libevent 2.0中,您可以使用event_active()從另一個線程激活一個事件。只要確保事先使用evthread_use_windows_threads()或evthread_use_pthreads(),就可以告訴Libevent使用正確的線程庫。

至於需要一個額外的事件:在Libevent 2.0和更早版本中,當沒有添加掛起事件時,事件循環將立即退出。你最好的選擇可能是你發現的超時技巧。

如果你不喜歡那樣,你可以使用內部的「event_base_add_virtual」函數告訴event_base它有一個虛擬事件。此功能不出口,雖然如此,你必須這樣說:

void event_base_add_virtual(struct event_base *); 
    // ... 
    base = event_base_new(); 
    event_base_add_virtual(base); // keep it from exiting 

這是一個黑客攻擊的一位,不過,它使用一個未公開的函數,所以你需要提防如果它不適用於更高版本的Libevent。

最後,這個方法現在不會幫助你,但有一個補丁等待未來版本的Libevent(2.1和更高版本)添加一個新的標誌到event_base_loop(),以防止它退出時,循環不存在事件。該補丁是over on Github;它主要是等待代碼審查,併爲選項命名更好。

+0

謝謝尼克的快速回復。 – Quentin

+0

我對此有幾點意見: - 至於我目前的項目,我認爲我可以通過略微不同地使用事件循環來解決這個問題,並且使用超時實際(不必要地)在相當長的等待後觸發處理1秒是服務器世界的永恆)。 - 爲什麼不能在fd或超時之前使用純粹的用戶觸發事件? - 如果事件將被忽略,event_add不應該返回0以外的東西嗎? 我受到event_base_add_virtual技巧的誘惑,但我更喜歡我的代碼與更高版本兼容。 – Quentin

+2

可以使用純粹的用戶觸發事件:你可以用event_new(base,-1/* no fd * /,0/* no events * /,callback,callback_data)製作它們。你用event_active()激活它們。但是,您不需要使用event_add():event_add()僅適用於基礎應爲其自身輪詢的事件。 – nickm

1

我剛剛被libevent-2.0.21-stable所燒燬。這顯然是一個錯誤。我希望他們在未來的版本中修復它。同時,更新文檔以警告我們會有所幫助。

最好的解決方法似乎是問題中所述的假超時。

@nickm,你沒有看過這個問題。他的示例代碼使用了您所描述的event_new(); libevent中有一個錯誤,導致它在使用NULL超時時失敗(但在調用event_add()時返回0)。