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);
    }
  • 相关阅读:
    爬取校园新闻首页的新闻的详情,使用正则表达式,函数抽离
    网络爬虫基础练习
    Mysql 使用 select into outfile
    Mysql 使用CMD 登陆
    使用Clean() 去掉由函数自动生成的字符串中的双引号
    Get Resultset from Oracle Stored procedure
    获取引用某个主键的所有外键的表
    Entity Framework 丢失数据链接的绑定,在已绑好的EDMX中提示“Choose Your Data Connection”
    添加MySql Metat Database 信息
    at System.Data.EntityClient.EntityConnection.GetFactory(String providerString)
  • 原文地址:https://www.cnblogs.com/milton/p/7980015.html
Copyright © 2011-2022 走看看