事件机制实现超时触发功能,同时捕捉Ctrl+C信号

来源:互联网 发布:大专php电商网站教程 编辑:程序博客网 时间:2024/04/30 00:07

更多代码详细请参见:https://github.com/wcwu/Timout-Event

超时事件任务包括几个部分:

  1. 事件结构体的构造;
  2. 事件的初始化;
  3. 事件的注册;
  4. 事件的删除;
  5. 事件的触发和执行。

 事件结构体构造:结构体包括两个部分,一个是事件本事的结构体,该结构体包含每个事件的节点信息,主要是每个节点的超时时间记录和超时处理函数。

typedef struct timeout_node{    int fnode_id;    uint64_t start_time;    uint64_t timeout;     handler_t func; }tnode;typedef struct timeout_event{    tnode** event_array;    int size;    int used;}tevent;
事件的初始化:初始化包括事件和节点两个部分,各初始化对应相应的free函数。

tevent* event_init(int max_event_num){    tevent* tv = (tevent*)malloc(sizeof(*tv));        tv->size = max_event_num;    tv->used = 0;    tv->event_array = calloc(max_event_num, sizeof(*tv->event_array));    assert(tv->event_array != NULL);    return tv;}void event_free(tevent *tv){    int i;    for(i = 0; i < tv->size; i++){        if(tv->event_array[i]){            free(tv->event_array[i]);        }    }    free(tv->event_array);    free(tv);}tnode* node_init(int id){    tnode* nd = calloc(1, sizeof(*nd));    nd->fnode_id = id;    nd->start_time = get_current_time();    nd->timeout = 0;    nd->func = NULL;}void node_free(tnode* nd){    free(nd);}

事件的注册:事件的注册主要是向事件列表中写入需要注册的节点.

void timeout_event_register(tevent*tv, int nid, uint64_t timeout, handler_t handler){    tnode* tnd = node_init(nid);    tnd->start_time = get_current_time();    tnd->func = handler;    tnd->timeout = timeout;    tv->event_array[tv->used] = tnd;    tv->used++;}int timeout_event_unregister(tevent*tv, int nid){    int i;    for(i = 0; i < tv->size; i++){        if(tv->event_array[i] && tv->event_array[i]->fnode_id == nid){            node_free(tv->event_array[i]);            tv->event_array[i] = NULL;            tv->used--;            return 1;        }    }    return 0;}

事件的触发和执行:指超时时间到达时,事件节点对应的函数handler将被执行.
void process_timeout(tevent *tv){    int i;     for(i = 0; i < tv->size; i++){        //printf("%ld, %ld, %ld\n", get_current_time(), tv->event_array[i]->start_time, tv->event_array[i]->timeout );        if(tv->event_array[i]){            if(get_current_time() > (tv->event_array[i]->start_time + tv->event_array[i]->timeout)){                tv->event_array[i]->func(tv->event_array[i]->fnode_id);                timeout_event_unregister(tv, tv->event_array[i]->fnode_id);            }        }    }}

一般来讲,我们的事件都会循环执行,判断事件列表中是否有超时事件.这时就要求我们捕捉来自键盘的或其他中断信号以释放内存资源,以键盘的SIGINT信号为例,捕捉信号的方法为通过设置一个全局变量来进行循环的终止.

volatile int srv_shutdown = 0;volatile int graceful_shutdown = 0;void sigHandler(int sig_num){    switch (sig_num) {        case SIGTERM: srv_shutdown = 1; break;        case SIGINT:                      if (graceful_shutdown) srv_shutdown = 1;                      else graceful_shutdown = 1;                      break;                      //       case SIGALRM: handle_sig_alarm = 1; break;                      //       case SIGHUP:  handle_sig_hup = 1; break;        case SIGCHLD:  break;    }}int main(){    struct sigaction act;    act.sa_handler = sigHandler;    sigaction(SIGINT, &act, NULL);    while(!srv_shutdown){        process_timeout(tv);         sleep(2);    }    if(srv_shutdown){        printf("The Event is shutted down!");        //free resource        event_free(tv);    }    return 0;}



0 0