zoukankan      html  css  js  c++  java
  • libevent源码分析:time-test例子

    time-test例子是libevent自带的一个例子,通过libevent提供的定时事件来实现,间隔固定时间打印的功能。

     1 /*
     2  * gcc -g -o time-test time-test.c -levent_core
     3  */
     4 
     5 #include <sys/types.h>
     6 #include <event2/event-config.h>
     7 #include <sys/stat.h>
     8 #include <unistd.h>
     9 #include <time.h>
    10 #include <sys/time.h>
    11 #include <fcntl.h>
    12 
    13 #include <stdlib.h>
    14 #include <stdio.h>
    15 #include <string.h>
    16 #include <errno.h>
    17 
    18 #include <event2/event.h>
    19 #include <event2/event_struct.h>
    20 #include <event2/util.h>
    21 
    22 struct timeval lasttime;
    23 int event_is_persistent;
    24 
    25 static void timeout_cb(evutil_socket_t fd, short event, void *arg)
    26 {
    27     struct timeval newtime, difference;
    28     struct event *timeout = arg;
    29     double elapsed;
    30 
    31     evutil_gettimeofday(&newtime, NULL);
    32     evutil_timersub(&newtime, &lasttime, &difference);
    33     elapsed = difference.tv_sec + (difference.tv_usec / 1.0e6);
    34 
    35     printf("timeout_cb called at %d: %.3f seconds elapsed.
    ", (int)newtime.tv_sec, elapsed);
    36     lasttime = newtime;
    37 
    38     if (!event_is_persistent)
    39     {
    40         struct timeval tv;
    41         evutil_timerclear(&tv);
    42         tv.tv_sec = 2;
    43         event_add(timeout, &tv);
    44     }
    45 }
    46 
    47 int main(int argc, char **argv)
    48 {
    49     struct event timeout;
    50     struct timeval tv;
    51     struct event_base *base;
    52     int flags;
    53 
    54     if (argc == 2 && strcmp(argv[1], "-p"))
    55     {
    56         event_is_persistent = 1;
    57         flags = EV_PERSIST;
    58     }
    59     else
    60     {
    61         event_is_persistent = 0;
    62         flags = 0;
    63     }
    64 
    65     /* Initalize the event library */
    66     base = event_base_new();
    67 
    68     /* Initalize one event */
    69     event_assign(&timeout, base, -1, flags, timeout_cb, (void*)&timeout);
    70 
    71     evutil_timerclear(&tv);
    72     tv.tv_sec = 20;
    73     event_add(&timeout, &tv);
    74 
    75     evutil_gettimeofday(&lasttime, NULL);
    76     event_base_dispatch(base);
    77 
    78     return 0;
    79 }
    View Code

    这次就通过分析一个这个简单的例子来加深对libevent的理解。

    1、首先通过event_base_new获取一个event_base对象。

    2、通过event_assign来对一个event赋值(属于的event_base,监听的事件类型,回调函数等)。

    3、通过event_add激活该event。

    4、调用event_base_dispatch进入事件循环。

    event_base_dispatch内部有一个很大的死循环,不停的调用io复用机制来监听指定文件描述符上的事件,并在相应事件发生的时候,触发相应的回调函数。

    回调的堆栈如下:

    可以看到是依次调用了event_base_loop()->event_process_active()->event_process_active_single_queue()->timeout_cb()。

      1 int
      2 event_base_loop(struct event_base *base, int flags)
      3 {
      4     const struct eventop *evsel = base->evsel;
      5     struct timeval tv;
      6     struct timeval *tv_p;
      7     int res, done, retval = 0;
      8 
      9     /* Grab the lock.  We will release it inside evsel.dispatch, and again
     10      * as we invoke user callbacks. */
     11     EVBASE_ACQUIRE_LOCK(base, th_base_lock);
     12 
     13     if (base->running_loop) {
     14         event_warnx("%s: reentrant invocation.  Only one event_base_loop"
     15             " can run on each event_base at once.", __func__);
     16         EVBASE_RELEASE_LOCK(base, th_base_lock);
     17         return -1;
     18     }
     19 
     20     base->running_loop = 1;
     21 
     22     clear_time_cache(base);
     23 
     24     if (base->sig.ev_signal_added && base->sig.ev_n_signals_added)
     25         evsig_set_base_(base);
     26 
     27     done = 0;
     28 
     29 #ifndef EVENT__DISABLE_THREAD_SUPPORT
     30     base->th_owner_id = EVTHREAD_GET_ID();
     31 #endif
     32 
     33     base->event_gotterm = base->event_break = 0;
     34 
     35     while (!done) {
     36         base->event_continue = 0;
     37         base->n_deferreds_queued = 0;
     38 
     39         /* Terminate the loop if we have been asked to */
     40         if (base->event_gotterm) {
     41             break;
     42         }
     43 
     44         if (base->event_break) {
     45             break;
     46         }
     47 
     48         tv_p = &tv;
     49         if (!N_ACTIVE_CALLBACKS(base) && !(flags & EVLOOP_NONBLOCK)) {
     50             timeout_next(base, &tv_p);
     51         } else {
     52             /*
     53              * if we have active events, we just poll new events
     54              * without waiting.
     55              */
     56             evutil_timerclear(&tv);
     57         }
     58 
     59         /* If we have no events, we just exit */
     60         if (0==(flags&EVLOOP_NO_EXIT_ON_EMPTY) &&
     61             !event_haveevents(base) && !N_ACTIVE_CALLBACKS(base)) {
     62             event_debug(("%s: no events registered.", __func__));
     63             retval = 1;
     64             goto done;
     65         }
     66 
     67         event_queue_make_later_events_active(base);
     68 
     69         clear_time_cache(base);
     70 
     71         res = evsel->dispatch(base, tv_p);
     72 
     73         if (res == -1) {
     74             event_debug(("%s: dispatch returned unsuccessfully.",
     75                 __func__));
     76             retval = -1;
     77             goto done;
     78         }
     79 
     80         update_time_cache(base);
     81 
     82         timeout_process(base);
     83 
     84         if (N_ACTIVE_CALLBACKS(base)) {
     85             int n = event_process_active(base);
     86             if ((flags & EVLOOP_ONCE)
     87                 && N_ACTIVE_CALLBACKS(base) == 0
     88                 && n != 0)
     89                 done = 1;
     90         } else if (flags & EVLOOP_NONBLOCK)
     91             done = 1;
     92     }
     93     event_debug(("%s: asked to terminate loop.", __func__));
     94 
     95 done:
     96     clear_time_cache(base);
     97     base->running_loop = 0;
     98 
     99     EVBASE_RELEASE_LOCK(base, th_base_lock);
    100 
    101     return (retval);
    102 }
    event_base_loop()

    其实如果去打开event_base_loop()函数的实现来看,会发现对于事件的处理时分两步的,先是调用dispatch,把不同io复用机制得到的事件转换为统一的libevent事件,并将这些事件放到event_base的激活事件队列中,然后再调用event_process_active函数从激活事件队列中挨个读取每个事件并调用其回调函数。

  • 相关阅读:
    Web项目发布步骤总结
    Web项目发布的一些设置
    阿里云部署Web项目
    Tomcat、Weblogic、WebSphere、JBoss服务器的选择
    EJB到底是什么
    数据库线程池3——现实中的参数
    数据库线程池2——线程池调优
    数据库线程池1——三种线程池的参数详细
    Mysql分页优化
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cardSalDao' defined in file [E:GItUppointerCard+redis argetgameCard-1.0-SNAPSHOTWEB-INFclassescnjbitdao
  • 原文地址:https://www.cnblogs.com/lit10050528/p/5868370.html
Copyright © 2011-2022 走看看