2011-10-04 12 views
8

Actualmente estoy escribiendo una aplicación multiproceso utilizando libevent.Evento desencadenado por el usuario en libevent

Algunos eventos son desencadenados por IO, pero necesito un par de eventos que se desencadenan a través de los hilos por el código en sí, utilizando event_active().

He tratado de escribir un programa simple que muestra dónde está mi problema:

El evento se crea utilizando event_new(), y el conjunto fd a -1.

Al llamar a event_add(), si se utiliza una estructura de tiempo de espera, Event event maneja adecuadamente el evento event_base_dispatch.

Si event_add (ev, NULL) se utiliza en lugar, devuelve 0 (al parecer con éxito), pero event_base_dispatch() devuelve 1 (lo que no significa que el evento no fue registrado correctamente.)

Este comportamiento se puede probar usando el siguiente código y el intercambio de las líneas 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; 
} 

de compilación: g ++ sample.cc -levent

lo que pasa es que no necesito el tiempo de espera, y no quiero usar un n-años tiempo de espera como solución alternativa. Entonces, si esta no es la forma correcta de usar eventos desencadenados por el usuario, me gustaría saber cómo se hace.

Respuesta

8

Su enfoque es el sonido. En Libevent 2.0, puede usar event_active() para activar un evento desde otro hilo. Solo asegúrese de usar evthread_use_windows_threads() o evthread_use_pthreads() según corresponda de antemano, para decirle a Libevent que use la biblioteca de threading correcta.

En cuanto a la necesidad de un evento adicional: en Libevent 2.0 y versiones anteriores, un ciclo de eventos se cerrará inmediatamente cuando no haya eventos pendientes agregados. Tu mejor apuesta es probablemente el truco de tiempo de espera que descubriste.

Si no te gusta, puedes usar la función interna "event_base_add_virtual" para decirle a la base de eventos que tiene un evento virtual. Esta función no se exporta, aunque, por lo que tendrá que decir algo como:

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

Eso es un poco de un corte, sin embargo, y se utiliza una función no documentada, por lo que había necesidad de mirar hacia fuera en caso de que no funcione con una versión posterior de Libevent.

Finalmente, este método no lo ayudará ahora, pero hay un parche pendiente para versiones futuras de Libevent (2.1 y posterior) para agregar una nueva marca a event_base_loop() para evitar que salga cuando el bucle está fuera de eventos. El parche es over on Github; está esperando principalmente la revisión del código y un mejor nombre para la opción.

+0

Gracias Nick por su rápida respuesta. – Quentin

+0

Tengo algunos comentarios al respecto: - En cuanto a mi proyecto actual, creo que puedo evitar esto utilizando el ciclo de eventos de forma ligeramente diferente y utilizando el tiempo de espera para activar (innecesariamente) el procesamiento después de una espera relativamente larga (1 segundo es una eternidad en el mundo de los servidores). - ¿Por qué no solo hace posible usar eventos puros desencadenados por el usuario además de fd o timeout? - Si se va a ignorar el evento, ¿no debería event_add devolver algo más que 0? Estaba tentado por el truco event_base_add_virtual, pero prefiero que mi código sea compatible con versiones posteriores. – Quentin

+2

Es posible usar eventos puros desencadenados por el usuario: los haces con event_new (base, -1/* no fd * /, 0/* sin eventos * /, devolución de llamada, callback_data). Los activas con event_active(). Sin embargo, no se les agrega event_add(): event_add() es solo para eventos que una base debe sondear por sí mismo. – nickm

1

Acabo de quemarme con libevent-2.0.21-stable. Es claramente un error. Espero que lo arreglen en una versión futura. Mientras tanto, sería útil actualizar los documentos para advertirnos al respecto.

La mejor solución parece ser el tiempo de espera falso descrito en la pregunta.

@nickm, usted no ha leído la pregunta. Su código de ejemplo usa event_new() como usted describió; hay un error en libevent que hace que falle al usar un tiempo de espera NULL (pero devuelve 0 cuando se llama a event_add()).

Cuestiones relacionadas