2012-06-20 25 views
5

La función principal se basa en libevent, pero hay una tarea a largo plazo en la función. Entonces inicie N pisadas para ejecutar las tareas. ¿Esta idea está bien? ¿Y cómo usar libevent y pthread juntos en C?Cómo usar libevent y pthread juntos en C

+0

Esto es bastante fácil de hacer con los procesos, si nos fijamos en el relay de OpenBSD, hay código para múltiples procesos que manejan las solicitudes entrantes. – tbert

Respuesta

1

Eso funcionaría.

En la función de devolución de llamada de E/S, delega el trabajo que consume mucho tiempo en otra secuencia de un grupo de subprocesos. La mecánica exacta depende de la interfaz del subproceso de trabajo o del grupo de subprocesos.

Para comunicar el resultado de la cadena de trabajo al hilo de E/S, utilice un tubo. El subproceso de trabajo escribe el puntero al objeto de resultado en el conducto y el subproceso de E/S se activa y lee el puntero del conducto.

1

Hay un ejemplo libevent multiproceso en esta entrada del blog: http://www.roncemer.com/multi-threaded-libevent-server-example

Su solución es, para citar:

La solución es crear una cola de eventos libevent (También conocido como event_base) por conexión activa , cada uno con su propio hilo de bomba de evento. Este proyecto hace exactamente eso, ofreciéndote todo lo que necesitas para escribir servidores de socket de alto rendimiento y multihilo, basados ​​en libevent.

+0

Enlace roto o tal vez el servidor está caído. Copie y pegue el código además de las URL en lugar de solo proporcionar los enlaces. – enthusiasticgeek

+1

@enthusiasticgeek, el servidor está activo y una búsqueda en su blog no muestra publicaciones en libevent, por lo que tal vez encontró un error y simplemente eliminó la publicación. Aquí hay una instantánea de la página de 2012: http://web.archive.org/web/20120707080222/http://www.roncemer.com/multi-threaded-libevent-server-example Aquí está el proyecto sourceforge vinculado- a partir de la instantánea: http://sourceforge.net/projects/libevent-thread/ No he mirado esto por un tiempo, pero puedes cortar y pegar código tú mismo si tienes la cabeza en el problema en este momento . – ahcox

+0

¡Gracias por los enlaces! – enthusiasticgeek

0

NOTA Esto es para libev no libevent pero la idea puede aplicarse.

Aquí presento un ejemplo para la comunidad. Coméntanos y avísame si hay errores notorios. Este ejemplo podría incluir un manejador de señal para la terminación de hilo y una salida elegante en el futuro.

//This program is demo for using pthreads with libev. 
//Try using Timeout values as large as 1.0 and as small as 0.000001 
//and notice the difference in the output 

//(c) 2009 debuguo 
//(c) 2013 enthusiasticgeek for stack overflow 
//Free to distribute and improve the code. Leave credits intact 
//compile using:   gcc -g test.c -o test -lpthread -lev 

#include <ev.h> 
#include <stdio.h> // for puts 
#include <stdlib.h> 
#include <pthread.h> 

pthread_mutex_t lock; 
double timeout = 0.00001; 
ev_timer timeout_watcher; 
int timeout_count = 0; 

ev_async async_watcher; 
int async_count = 0; 

struct ev_loop* loop2; 

void* loop2thread(void* args) 
{ 
    // now wait for events to arrive on the inner loop 
    ev_loop(loop2, 0); 
    return NULL; 
} 

static void async_cb (EV_P_ ev_async *w, int revents) 
{ 
    //puts ("async ready"); 
    pthread_mutex_lock(&lock);  //Don't forget locking 
    ++async_count; 
    printf("async = %d, timeout = %d \n", async_count, timeout_count); 
    pthread_mutex_unlock(&lock); //Don't forget unlocking 
} 

static void timeout_cb (EV_P_ ev_timer *w, int revents) // Timer callback function 
{ 
    //puts ("timeout"); 
    if(ev_async_pending(&async_watcher)==false){ //the event has not yet been processed (or even noted) by the event loop? (i.e. Is it serviced? If yes then proceed to) 
     ev_async_send(loop2, &async_watcher); //Sends/signals/activates the given ev_async watcher, that is, feeds an EV_ASYNC event on the watcher into the event loop. 
    } 

    pthread_mutex_lock(&lock);  //Don't forget locking 
    ++timeout_count; 
    pthread_mutex_unlock(&lock); //Don't forget unlocking 
    w->repeat = timeout; 
    ev_timer_again(loop, &timeout_watcher); //Start the timer again. 
} 

int main (int argc, char** argv) 
{ 
    if (argc < 2) { 
     puts("Timeout value missing.\n./demo <timeout>"); 
     return -1; 
    } 
    timeout = atof(argv[1]); 

    struct ev_loop *loop = EV_DEFAULT; //or ev_default_loop (0); 

    //Initialize pthread 
    pthread_mutex_init(&lock, NULL); 
    pthread_t thread; 

    // This loop sits in the pthread 
    loop2 = ev_loop_new(0); 

    //This block is specifically used pre-empting thread (i.e. temporary interruption and suspension of a task, without asking for its cooperation, with the intention to resume that task later.) 
    //This takes into account thread safety 
    ev_async_init(&async_watcher, async_cb); 
    ev_async_start(loop2, &async_watcher); 
    pthread_create(&thread, NULL, loop2thread, NULL); 

    ev_timer_init (&timeout_watcher, timeout_cb, timeout, 0.); // Non repeating timer. The timer starts repeating in the timeout callback function 
    ev_timer_start (loop, &timeout_watcher); 

    // now wait for events to arrive on the main loop 
    ev_loop(loop, 0); 
    //Wait on threads for execution 
    pthread_join(thread, NULL); 

    pthread_mutex_destroy(&lock); 
    return 0; 
} 
0

Al responder una pregunta anterior, puede que ya se haya resuelto. Pero publicar la respuesta por si acaso alguien más la necesita.

Sí, está bien enhebrar en este caso. Recientemente utilicé libevent en pthreads, y parece estar funcionando bien. Aquí está el código:

#include <stdint.h> 
#include <pthread.h> 
#include <event.h> 

void * thread_func (void *); 

int main(void) 
{ 
    int32_t tid = 0, ret = -1; 
    struct event_base *evbase; 
    struct event *ev; 
    int32_t *t_ret = &ret; 
    struct timeval tv; 

    // 1. initialize libevent for pthreads 
    evthread_use_pthreads(); 

    ret = pthread_create(&tid, NULL, thread_func, NULL); 
    // check ret for error 

    // 2. allocate event base 
    evbase = event_base_new(); 
    // 3. allocate event object 
    timer = event_new(evbase, -1, EV_PERSIST, callback_func, NULL); 
    // 4. add event 
    tv.tv_sec = 0; 
    tv.tv_usec = 1000; 
    evtimer_add(timer, &tv); 
    // 5. start the event loop 
    event_base_dispatch(evbase); // event loop 

    // join pthread... 

    // 6. free resources 
    event_free(timer); 
    event_base_free(evbase); 
    return 0; 
} 

void * thread_func(void *arg) 
{ 
    struct event *ev; 
    struct event_base *base; 

    base = event_base_new(); 
    ev = event_new(base, -1, EV_PERSIST, thread_callback, NULL); 
    event_add(ev, NULL); // wait forever 
    event_base_dispatch(base); // start event loop 

    event_free(ev); 
    event_base_free(base); 
    pthread_exit(0); 
} 

Como puede ver, en mi caso, el evento para el hilo principal es el temporizador. La lógica es una base seguido de la siguiente manera:

  1. llamada evthread_use_pthreads() para inicializar libevent para pthreads en Linux (mi caso). Para Windows evthread_use_window_threads(). Consulte la documentación que se proporciona en el event.h.
  2. Asigne una estructura de event_base en el montón global tal como se indica en la documentación. Asegúrese de verificar el valor devuelto para ver si hay errores.
  3. Igual que el anterior, pero asignar evento estructura en sí. En mi caso, no estoy esperando ningún descriptor de archivo, por lo que -1 se pasa como argumento. Además, quiero que mi evento persista, por lo tanto, EV_PERSIST. El código para las funciones de devolución de llamada se omite.
  4. programar el evento para su ejecución
  5. Iniciar el ciclo de eventos
  6. libres los recursos cuando haya terminado.

versión libevent utilizado en mi caso es libevent2 5.1.9, y usted también tendrá que necesite libevent_pthreads.so biblioteca para vincular.

aplausos.