2012-06-20 10 views
5

Główna funkcja opiera się na libevent, ale w tej funkcji jest długotrwałe zadanie. Więc zacznij N kroków, aby uruchomić zadania. Czy ten pomysł jest OK? I jak korzystać z libevent i pthread razem w C?Jak korzystać z libevent i pthread razem w C

+0

Jest to dość łatwe do zrobienia z procesami, jeśli spojrzeć na przekazane przez OpenBSD, istnieje kod dla wielu procesów obsługujących przychodzące żądania. – tbert

Odpowiedz

1

To by działało.

W funkcji wywołania zwrotnego we/wy deleguje czasochłonne zadanie do innego wątku puli wątków. Dokładna mechanika zależy od interfejsu wątku roboczego lub puli wątków.

Aby przekazać wynik z powrotem z wątku roboczego do wątku I/O, użyj potoku. Wątek roboczy zapisuje wskaźnik do obiektu wynikowego na rurze, a wątek I/O budzi się i odczytuje wskaźnik z rury.

1

Jest to wielowątkowy libevent przykładem w tym blogu: http://www.roncemer.com/multi-threaded-libevent-server-example

Jego rozwiązaniem jest, aby zacytować:

Rozwiązaniem jest stworzenie jednej kolejki zdarzeń libevent (AKA event_base) na aktywnym połączeniu , każdy z własnym gwintem pompy zdarzenia. Ten projekt ma dokładnie to, co daje ci wszystko, czego potrzeba do tworzenia wysokowydajnych, wielowątkowych, opartych na libevent serwerów gniazd.

+0

Zepsuty link lub serwer jest wyłączony. Skopiuj i wklej kod oprócz adresów URL, a nie tylko linki. – enthusiasticgeek

+1

@enthusiasticgeek, Serwer jest uruchomiony i jego blog na blogu nie zawiera postów dotyczących libevent, więc może znalazł błąd i właśnie usunął wpis. Oto migawka strony z 2012 roku: http://web.archive.org/web/20120707080222/http://www.roncemer.com/multi-threaded-libevent-server-example Tutaj jest projekt sourceforge połączony- na podstawie migawki: http://sourceforge.net/projects/libevent-thread/ Nie patrzyłem na to od jakiegoś czasu, ale możesz samodzielnie wyciąć i wkleić kod, jeśli masz już problem z głową . – ahcox

+0

Dzięki za linki! – enthusiasticgeek

0

UWAGA To jest dla libev nie libevent, ale pomysł może mieć zastosowanie.

Tutaj przedstawiam przykład dla społeczności. Proszę skomentuj i daj mi znać, jeśli pojawią się jakieś zauważalne błędy. Ten przykład może zawierać procedurę obsługi sygnału dla zakończenia wątku i płynnego wyjścia w przyszłości.

//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

Wpadnięcie na stare pytanie mogło już zostać rozwiązane. Ale zamieszczanie odpowiedzi na wypadek, gdyby ktoś jej potrzebował.

Tak, nic nie szkodzi powielaniu w tym przypadku. Ostatnio użyłem libevent w pthreads i wygląda na to, że działa dobrze. Oto kod:

#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); 
} 

Jak widać, w moim przypadku wydarzenie dla głównego wątku to timer. Logika baza następnie jest jak poniżej:

  1. wezwanie evthread_use_pthreads() zainicjować biblioteki libevent dla pthreads na Linux (moim przypadku). Dla okien evthread_use_window_threads(). Sprawdź samą dokumentację podaną w event.h.
  2. Przydziel strukturę event_base na globalnej stercie zgodnie z instrukcją w dokumentacji. Upewnij się, że zwracasz wartość błędów.
  3. To samo co powyżej, ale przydzielać samą strukturę zdarzenie. W moim przypadku nie czekam na deskryptor pliku, więc -1 jest przekazywane jako argument. Ponadto chcę, aby moje wydarzenie się utrzymywało, stąd EV_PERSIST. Kod funkcji zwrotnych jest pominięty.
  4. Harmonogram imprezy dla realizacji
  5. Uruchom pętli zdarzeń
  6. wolnych zasobów po zakończeniu.

wersja libevent stosowany w moim przypadku jest libevent2 5.1.9, a także potrzebują libevent_pthreads.so bibliotekę do linkowania.

okrzyki.