zoukankan      html  css  js  c++  java
  • Libevent官方代码样例学习(一)

    在Ubuntu16.04中, libevent的默认安装位置为

    #在 trusty 发行版中 amd64 硬件架构下的 libevent-2.0-5 软件包文件清单
    /usr/lib/x86_64-linux-gnu/libevent-2.0.so.5
    /usr/lib/x86_64-linux-gnu/libevent-2.0.so.5.1.9
    /usr/share/doc/libevent-2.0-5/changelog.Debian.gz
    /usr/share/doc/libevent-2.0-5/copyright

    https://github.com/libevent/libevent/blob/master/sample/time-test.c

    这是一个定时触发事件的例子, 根据输入参数的不同, 单次执行或持续执行.

    在main方法中, 通过以下的方法调用将timeout_event加入到将来的事件中.

    base = event_base_new();
    struct event timeout; event_assign(
    &timeout_event, base, -1, flags, timeout_callback, (void *) &timeout_event); event_add(timeout_event, &tv); event_base_dispatch(base);

    将timeout_event作为参数传入callback方法, 然后在callback方法中再次将timeout_event加入到将来的事件中

    struct event *timeout_event = arg;
    // ...
    event_add(timeout_event, &tv);

    在这种情况下, 原代码中的flags = EV_PERSIST其实是不起作用的, 因为callback中复用了原来的内存地址, 设置为flags = 0一样能持续执行.

    如果将event_assign改为event_new, 则调用变为

    base = event_base_new();
    // 注意此处不传入event而传入event_base, 因为event在当前方法中new并alloca空间, 所以传入的event指针是无效的.
    struct event *timeout_event = event_new(base, -1, flags, timeout_callback, base);
    event_add(timeout_event, &tv);
    evutil_gettimeofday(&lasttime, NULL);
    event_base_dispatch(base);

    而callback中的处理变为

    struct event_base *base = arg;
    struct event *timeout_event = event_new(base, -1, 0, timeout_callback, base);
    event_add(timeout_event, &tv);

    这时候, 如果代码中使用flags = EV_PERSIST就会产生内存泄漏, 因为在触发后并不释放, 会持续的每隔1秒调用callback, 这时候要么在callback中不新增event, 要么flag设为0.

    修改后的代码:

    /*
     * XXX This sample code was once meant to show how to use the basic Libevent
     * interfaces, but it never worked on non-Unix platforms, and some of the
     * interfaces have changed since it was first written.  It should probably
     * be removed or replaced with something better.
     *
     * Compile with:
     * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
     */
    
    #include <sys/types.h>
    
    #ifndef _WIN32
    #include <sys/queue.h>
    #include <unistd.h>
    #endif
    #ifdef EVENT__HAVE_SYS_TIME_H
    #include <sys/time.h>
    #endif
    
    #include <stdio.h>
    #include <string.h>
    
    #include <event2/event.h>
    #include <event2/event_struct.h>
    
    #ifdef _WIN32
    #include <winsock2.h>
    #endif
    
    struct timeval lasttime;
    int event_is_persistent;
    
    static void
    timeout_callback(evutil_socket_t fd, short event, void *arg) {
        struct timeval newtime, difference;
        struct event_base *base = arg;
        double elapsed;
    
        // The evutil_gettimeofday function sets tv to the current time. The second argument is unused.
        evutil_gettimeofday(&newtime, NULL);
        // This macro subtract (respectively) their first two arguments, and stores the result in the third.
        evutil_timersub(&newtime, &lasttime, &difference);
        elapsed = difference.tv_sec + (difference.tv_usec / 1.0e6);
        printf("timeout_callback called at %d: %.3f seconds elapsed.
    ", (int) newtime.tv_sec, elapsed);
        lasttime = newtime;
        if (event_is_persistent == 1) {
            struct event *timeout_event = event_new(base, -1, 0, timeout_callback, base);
            struct timeval tv;
            evutil_timerclear(&tv);
            tv.tv_sec = 0;
            tv.tv_usec = 10000;
            event_add(timeout_event, &tv);
        }
    }
    
    int
    main(int argc, char **argv) {
        struct timeval tv;
        struct event_base *base;
        int flags;
        // strcmp: <0 the first character that does not match has a lower value in ptr1 than in ptr2
        // 0 the contents of both strings are equal
        // >0 the first character that does not match has a greater value in ptr1 than in ptr2
        if (argc == 2 && !strcmp(argv[1], "-p")) {
            event_is_persistent = 1;
            // Use this if you use event_new instead of event_assign
            flags = 0;
        } else {
            event_is_persistent = 0;
            flags = 0;
        }
        /* Initalize the event library */
        base = event_base_new();
        /*
         * Prepare a new, already-allocated event structure to be added.
         * The function event_assign() prepares the event structure ev to be used in future calls to event_add() and event_del().
         * Unlike event_new(), it doesn't allocate memory itself: it requires that you have already allocated a struct event,
         * probably on the heap. Doing this will typically make your code depend on the size of the event structure, and thereby
         * create incompatibility with future versions of Libevent.
         * The easiest way to avoid this problem is just to use event_new() and event_free() instead.
         * A slightly harder way to future-proof your code is to use event_get_struct_event_size() to determine the required size
         * of an event at runtime.
         * Note that it is NOT safe to call this function on an event that is active or pending. Doing so WILL corrupt internal
         * data structures in Libevent, and lead to strange, hard-to-diagnose bugs. You can use event_assign to change an existing
         * event, but only if it is not active or pending!
         */
        //event_assign(&timeout_event, base, -1, flags, timeout_callback, (void *) &timeout_event);
        struct event *timeout_event = event_new(base, -1, flags, timeout_callback, base);
    
        // Set (tvp)->tv_sec and (tvp)->tv_usec to 0
        evutil_timerclear(&tv);
        tv.tv_sec = 1;
        // Add an event to the set of pending events.
        // The function event_add() schedules the execution of the ev event when the event specified in event_assign()/event_new() occurs,
        // or when the time specified in timeout has elapesed. If atimeout is NULL, no timeout occurs and the function will only be called
        // if a matching event occurs. The event in the ev argument must be already initialized by event_assign() or event_new() and may
        // not be used in calls to event_assign() until it is no longer pending.
        // If the event in the ev argument already has a scheduled timeout, calling event_add() replaces the old timeout with the new one,
        // or clears the old timeout if the timeout argument is NULL.
        event_add(timeout_event, &tv);
        evutil_gettimeofday(&lasttime, NULL);
        event_base_dispatch(base);
    
        return (0);
    }

    Update 2017-12-05:

    如果使用的是libevent 2.1.1以后的版本, 可以使用event_self_cbarg()方法. 在event_new中通过 event_self_cbarg() 方法传入自身指针.

    #include <event2/event.h>
    static int n_calls = 0;
    
    void cb_func(evutil_socket_t fd, short what, void *arg){
        struct event *me = arg;
        printf("cb_func called %d times so far.
    ", ++n_calls);
        if (n_calls > 100)
           event_del(me);
    }
    
    void run(struct event_base *base){
        struct timeval one_sec = { 1, 0 };
        struct event *ev;
        /* We're going to set up a repeating timer to get called called 100 times. */
        ev = event_new(base, -1, EV_PERSIST, cb_func, event_self_cbarg());
        event_add(ev, &one_sec);
        event_base_dispatch(base);
    }
  • 相关阅读:
    网络资源
    为什么MVC不是一种设计模式? ---比较Backbone和Ext4.x在MVC实现上的差异
    Developing Backbone.js Applications
    【实例】爬虫:下载图片
    scheme语言编写执行
    HDU 4403 A very hard Aoshu problem (DFS暴力)
    【Python】输出程序运行的百分比
    SQL_字符操作函数
    Linux mm相关的问题
    java中Volatile修饰符的含义
  • 原文地址:https://www.cnblogs.com/milton/p/7980015.html
Copyright © 2011-2022 走看看