如何打破 libevent 的调度循环



我在一个单独的线程中使用漂亮的libevent库实现了一个小型Web服务器。Web服务器运行event_base_dispatch()来处理所有事件。我需要的是一种从主线程中断这个调度循环的方法。

它可以归结为以下C++代码:

#include <stdlib.h>
#include <signal.h>
#include <thread>
#include <evhttp.h>
struct event_base *eb;
std::thread t;
static volatile sig_atomic_t bailout = false;
void my_signal_handler(int) {
    bailout = true;
}
void onRequest(evhttp_request *req, void *) {
    struct evbuffer *OutBuf = evhttp_request_get_output_buffer(req);
    evbuffer_add_printf(OutBuf, "<html><body>Testing 1-2-3</body></html>");
    evhttp_send_reply(req, HTTP_OK, "OK", OutBuf);
}
void dispatch() {
    eb = event_base_new();
    struct evhttp *http = evhttp_new(eb);
    evhttp_set_gencb(http, &onRequest, NULL);
    evhttp_bind_socket_with_handle(http, "0.0.0.0", 5555);
    event_base_dispatch(eb);
}
int main() {
    struct sigaction sigIntHandler;
    sigIntHandler.sa_handler = my_signal_handler;
    sigemptyset(&sigIntHandler.sa_mask);
    sigIntHandler.sa_flags = 0;
    sigaction(SIGINT, &sigIntHandler, NULL);
    t = std::thread { &dispatch };
    while ( ! bailout ) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
    event_base_loopexit(eb, NULL);
    t.join();
}

其行为是,如果您运行程序、请求页面、按Ctrl-C中止程序,event_base_dispatch()将继续运行,直到获取另一个网页。只有这样循环才会中止,程序才会终止。

如果在运行更多回调之前需要退出事件循环,请使用event_base_break()

http://www.wangafu.net/~nickm/libfevent-book/Ref3_eventloop.html#_stopping_the_loop

最后,我通过添加一个计时器来打破调度循环,该计时器基本上轮询救援变量:

struct event *ev;
const struct timeval one_sec = { 1, 0 }; // sec, usec
void cb_timer_func(evutil_socket_t, short, void) {
  if ( bailout ) {
    event_base_loopbreak(eb);
  }
  else if ( ! evtimer_pending(ev, NULL) ) {
    evtimer_del(ev);
    evtimer_add(ev, &one_sec);
  }
}

在调度循环中,我补充道:

ev = evtimer_new(eb, cb_timer_func);
evtimer_add(ev, &one_sec);
还有一种方法是将event_base_loopbreak()放入信号处理程序中。

最新更新