libevent之 C++ RAII封裝 定時器
前言:
這兩天讀Bitcoin程式碼,不禁感慨作者的強大,程式碼的精妙不是我這碼農虔誠膜拜便能讀懂的,更遠遠談不上企及。於是默默埋頭,回想本屌,工作七年還是個默默無聞不及格的碼農,黯然內流~~
C/C++那種非人性化的吐槽:
相信很多童鞋跟本農一樣,吃過飯之後就是不想洗碗收拾桌子。那太麻煩了,像我們這樣怕麻煩的,吃飯首選快餐。以致於錯過了自己做飯的樂趣。C/C++就是這樣麻煩的發明,效率高不說,可就是要擦屁股,使用malloc/calloc/new等分配的指標所總是要我們自己去回收,多費事啊,為何他們就不能像java那邊智慧一點呢。當然C++有智慧指標,相比C好多了,可依舊麻煩。繞不開這兩種語言的只能含淚硬上了。
閒話少說,進入主題:libevent RAII封裝
只帖一部分,摘Bitcoin的,其他的自己擴充套件了。
有這些封裝就不用管資源的回收了。#include <event2/event.h> #include <event2/listener.h> #define MAKE_RAII(type) \ /* deleter */\ struct type##_deleter {\ void operator()(struct type* ob) {\ type##_free(ob);\ }\ };\ /* unique ptr typedef */\ typedef std::unique_ptr<struct type, type##_deleter> raii_##type MAKE_RAII(event_base); MAKE_RAII(event); MAKE_RAII(evconnlistener); inline raii_event_base obtain_event_base() { auto result = raii_event_base(event_base_new()); if (!result.get()) throw std::runtime_error("cannot create event_base"); return result; } inline raii_event obtain_event(struct event_base* base, evutil_socket_t s, short events, event_callback_fn cb, void* arg) { return raii_event(event_new(base, s, events, cb, arg)); } inline raii_evconnlistener obtain_evconnlistener(struct event_base *base, evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, const struct sockaddr *sa, int socklen) { return raii_evconnlistener( evconnlistener_new_bind(base, cb, ptr, flags, backlog, sa, socklen)); }
例項:
定時器每兩秒鐘回撥一次,迴圈列印。
#include <memory> #include <event2/event-config.h> #include <event2/event.h> #include <event2/event_struct.h> #include <event2/util.h> #include <event2/listener.h> #include <stdio.h> #include <iostream> using namespace std; #define MAKE_RAII(type) \ /* deleter */\ struct type##_deleter {\ void operator()(struct type* ob) {\ type##_free(ob);\ }\ };\ /* unique ptr typedef */\ typedef std::unique_ptr<struct type, type##_deleter> raii_##type MAKE_RAII(event_base); MAKE_RAII(event); MAKE_RAII(evconnlistener); inline raii_event_base obtain_event_base() { auto result = raii_event_base(event_base_new()); if (!result.get()) throw std::runtime_error("cannot create event_base"); return result; } inline raii_event obtain_event(struct event_base* base, evutil_socket_t s, short events, event_callback_fn cb, void* arg) { return raii_event(event_new(base, s, events, cb, arg)); } inline raii_evconnlistener obtain_evconnlistener(struct event_base *base, evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, const struct sockaddr *sa, int socklen) { return raii_evconnlistener( evconnlistener_new_bind(base, cb, ptr, flags, backlog, sa, socklen)); } struct timeval lasttime; static void timeoutCallback(evutil_socket_t fd, short event, void *arg) { struct timeval newtime, difference; struct event *timeout = (struct event *)arg; double elapsed; struct timeval tv{2,0}; evutil_gettimeofday(&newtime, NULL); evutil_timersub(&newtime, &lasttime, &difference); elapsed = difference.tv_sec + (difference.tv_usec / 1.0e6); cout << "timeoutCallback called at "<<newtime.tv_sec << elapsed << " seconds elapsed."<<endl; lasttime = newtime; // evutil_timerclear(&tv); // tv.tv_sec = 2; event_add(timeout, &tv); } int main(int argc, char **argv) { struct timeval tv{2,0}; int flags; flags = EV_PERSIST; // Obtain event base auto raii_base = obtain_event_base(); auto raii_event = obtain_event(raii_base.get(), -1, 0, nullptr, nullptr); /* Initalize one event */ event_assign(raii_event.get(), raii_base.get(), -1, flags, timeoutCallback, (void*) raii_event.get()); // evutil_timerclear(&tv); // tv.tv_sec = 2; event_add(raii_event.get(), &tv); evutil_gettimeofday(&lasttime, NULL); event_base_dispatch(raii_base.get()); return 0; }
輸出:
timeoutCallback called at 15259423982.001 seconds elapsed.
timeoutCallback called at 15259424002.001 seconds elapsed.
timeoutCallback called at 15259424022.001 seconds elapsed.
timeoutCallback called at 15259424042.001 seconds elapsed.
timeoutCallback called at 15259424062.001 seconds elapsed.
timeoutCallback called at 15259424082.001 seconds elapsed.
timeoutCallback called at 15259424102.001 seconds elapsed.