1. 程式人生 > >時間堆實現定時器

時間堆實現定時器

時間堆:將所有定時器中超時最小的一個作為心搏間隔,這樣,一旦心搏函式tick被呼叫,超時時間最小的一個定時器必然到期,我們就可以在tick函式裡處理該定時器,這樣就實現了較為精確的定時.

最小堆很適合這種方案,最小堆的堆頂永遠為最小的元素,這樣每次只要將堆頂的定時器處理,並將下一個堆頂元素的超時時間作為下一次心搏間隔即可實現上述方案

#ifndef _MIN_HEAP_H
#define _MIN_HEAP_H

#include<iostream>
#include<netinet/in.h>
#include<time.h>
using std::exception;

#define BUFFER_SIZE 64

class heap_timer;

class client_data
{
public:
    sockaddr_in address;
    int sockfd;
    char buf[BUFFER_SIZE];
    heap_timer *timer;
};
class heap_timer
{
public:
    heap_timer(int delay)
    {
        expire = time(NULL)+delay;
    }
    time_t expire;
    void (*cb_func)(client_data*);
    client_data *user_data;
};

class time_heap
{
public:
    time_heap(int cap)throw(std::exception):capacity(cap),cur_size(0)
    {
        array = new heap_timer*[capacity];
        if(!array)
        {
            throw std::exception();
        }
        for(int i = 0;i<capacity;++i)
        {
            array[i] = NULL;
        }
    }
    time_heap(heap_timer** init_array,int size,int capacity) throw(std::exception):cur_size(size),capacity(capacity)
    {
        if(capacity<size)
        {
            throw std::exception();
        }
        array = new heap_timer* [capacity];
        if(!array)
        {
            throw std::exception();
        }
        for(int i=0;i<capacity;++i)
        {
            array[i] = NULL;
        }
        if(!size)
        {
            for(int i=0;i<size;++i)
            {
                array[i] = init_array[i];
            }
            for(int i = (cur_size-1)/2;i>=0;--i)
            {
                percolate_down(i);
            }
        }
    }
    ~time_heap()
    {
        for(int i = 0;i<cur_size;++i)
        {
            delete array[i];
        }
        delete []array;
    }
    void add_timer(heap_timer *timer) throw(std::exception)
    {
        if(!timer)
        {
            return;
        }
        if(cur_size >= capacity)
        {
            resize();
        }
        int hole = cur_size++;
        int parent = 0;
        for(; hole > 0;hole = parent)
        {
            parent = (hole-1)/2;
            if(array[parent]->expire <= timer->expire)
            {
                break;
            }
            array[hole] = array[parent];
        }
        array[hole] = timer;
    }
    void del_timer(heap_timer* timer)
    {
        if(!timer)
        {
            return;
        }
        timer->cb_func = NULL;//延遲銷燬
    }
    heap_timer* top()const
    {
        if(empty())
        {
            return NULL;
        }
        return array[0];
    }
    void pop_timer()
    {
        if(empty())
        {
            return;
        }
        if(array[0])
        {
            delete array[0];
            array[0] = array[--cur_size];
            percolate_down(0);
        }
    }
    void tick()
    {
        heap_timer *tmp = array[0];
        time_t cur = time(NULL);
        while(!empty())
        {
            if(!tmp)
            {
                break;
            }
            if(tmp->expire > cur)
            {
                break;
            }
            if(array[0]->cb_func)
            {
                array[0]->cb_func(array[0]->user_data);
            }
            pop_timer();
            tmp = array[0];
        }
    }
    bool empty()const
    {
        return cur_size == 0;
    }


private:

    void percolate_down(int hole)
    {
        heap_timer* temp = array[hole];
        int child = 0;
        for( ;((hole*2+1) <= (cur_size-1));hole = child)
        {
            child = (hole*2+1);
            if( (child < (cur_size-1) ) && (array[child+1]->expire < array[child]->expire) )
            {
                ++child;
            }
            if( array[child]->expire < temp->expire)
            {
                array[hole] = array[child];
            }
            else
            {
                break;
            }
        }
        array[hole] = temp;
    }
    void resize()throw(std::exception)
    {
        heap_timer** temp = new heap_timer*[2*capacity];
        for(int i=0;i<2*capacity;++i)
        {
            temp[i] = NULL;
        }
        if(!temp)
        {
            throw std::exception();
        }
        capacity = 2*capacity;
        for(int i=0;i<cur_size;++i)
        {
            temp[i] = array[i];
        }
        delete []array;
        array = temp;
    }
    heap_timer** array;
    int capacity;
    int cur_size;
};

#endif

ser.cpp

#include"./utili.h"
#include"./min_heap.h"

#define FD_LIMIT 65535
#define MAX_EVENT_NUMBER 1024
#define TIMESLOT 10
using namespace std;
static int pipefd[2];
static time_heap th(10);
static int epollfd = 0;

int setnonblocking(int fd)
{
    int old_option = fcntl(fd,F_GETFL);
    int new_option = old_option|O_NONBLOCK;
    fcntl(fd,F_SETFL,new_option);
    return old_option;
}
void addfd(int epollfd,int fd)
{
    epoll_event event;
    event.data.fd = fd;
    event.events = EPOLLIN | EPOLLET;
    epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&event);
    setnonblocking(fd);
}
void sig_handler(int sig)
{
    int save_errno = errno;
    int msg = sig;
    send(pipefd[1],(char*)&msg,1,0);
    errno = save_errno;
}
void time_handler()
{
    th.tick();
    if(!th.empty())
    alarm((th.top()->expire-time(NULL)));//將定時器中最小超時時間(即堆頂計時器的超時時間)作為下一次心搏時間,這樣可以減少tick函式被呼叫的次數,保證每次呼叫必然都有超時事件發生
    else
    alarm(TIMESLOT);
}
void addsig(int sig)
{
    struct sigaction sa;
    memset(&sa,'\0',sizeof(sa));
    sa.sa_handler = sig_handler;
    sa.sa_flags |=SA_RESTART;
    sigfillset(&sa.sa_mask);
    assert(sigaction(sig,&sa,NULL)!=-1);
}
void cb_func(client_data* user_data)
{
    epoll_ctl(epollfd,EPOLL_CTL_DEL,user_data->sockfd,0);
    assert(user_data);
    char buf[38]= "long time no request,you are closed.";
    send(user_data->sockfd,buf,strlen(buf),0);
    close(user_data->sockfd);
    printf("cllose fd %d\n",user_data->sockfd);
}

int main(int argc,char *argv[])
{
    if(argc<=2)
    {
        printf("usage: %s  ip  port_number\n",basename(argv[0]));
        return 1;
    }
    const char *ip = argv[1];
    int port = atoi(argv[2]);

    struct sockaddr_in address;
    bzero(&address,sizeof(address));
    address.sin_family = AF_INET;
    address.sin_port = htons(port);
    inet_pton(AF_INET,ip,&address.sin_addr);

    int sock = socket(AF_INET,SOCK_STREAM,0);
    assert(sock>=0);

    int ret = bind(sock,(struct sockaddr*)&address,sizeof(address));
    assert(ret!=-1);

    ret = listen(sock,5);
    assert(ret!=-1);
    
    epoll_event events[MAX_EVENT_NUMBER];
    int epollfd = epoll_create(5);
    assert(epollfd!=-1);
    addfd(epollfd,sock);

    ret = socketpair(PF_UNIX,SOCK_STREAM,0,pipefd);
    if(ret == -1)
    {
        printf("errno = %d\n",errno);

    assert(ret!=-1);
    }
    setnonblocking(pipefd[1]);
    addfd(epollfd,pipefd[0]);

    addsig(SIGTERM);
    addsig(SIGALRM);

    int stop_sever = 0;

    client_data* users = new client_data[MAX_EVENT_NUMBER];
    int timeout = 0;
    alarm(TIMESLOT);

    while(!stop_sever)
    {
        int number = epoll_wait(epollfd,events,MAX_EVENT_NUMBER,-1);
        if(number<0)
        {
            if(errno == EINTR)
            {
                continue;
            }
            else
            {
                printf("errno =  %d\n",errno);
                printf("epoll_wait fail\n");
                break;
            }
        }
        int i=0;
        for(;i<number;++i)
        {
            int sockfd = events[i].data.fd;

            if(sockfd == sock)
            {
                struct sockaddr_in client;
                socklen_t len = sizeof(client);
                int connfd = accept(sock,(struct sockaddr*)&client,&len);
                addfd(epollfd,connfd);
                users[connfd].address = client;
                users[connfd].sockfd = connfd;

                heap_timer* timer = new heap_timer(10);//**
                timer->user_data = &users[connfd];
                timer->cb_func = cb_func;
                time_t cur = time(NULL);
                timer->expire = cur +3*TIMESLOT;
                users[connfd].timer = timer;
                th.add_timer(timer);
            }
            else if((sockfd == pipefd[0])&&(events[i].events & EPOLLIN))
            {
                int sig;
                char signals[1024];
                ret = recv(pipefd[0],signals,sizeof(signals),0);
                if(ret == -1)
                {
                    //handle errno
                    continue;
                }
                else if(ret == 0)
                {
                    continue;
                }
                else
                {
                    int i=0;
                    for(;i<ret;++i)
                    {
                        switch(signals[i])
                        {
                            case SIGALRM:
                            {
                                timeout = 1;
                                break;
                            }
                            case SIGTERM:
                            {
                                stop_sever = 1;
                            }
                        }
                    }
                }
            }
            else if(events[i].events & EPOLLIN)
            {
                memset(users[sockfd].buf,'\0',BUFFER_SIZE);
                ret = recv(sockfd,users[sockfd].buf,BUFFER_SIZE-1,0);
                heap_timer* timer = users[sockfd].timer;
                if(ret<0)
                {
                    if(errno!=EAGAIN)
                    {    
                        cb_func(&users[sockfd]);
                        if(timer)
                        {
                            th.del_timer(timer);
                        }
                    }
                }
                else if(ret == 0)
                {
                    cb_func(&users[sockfd]);
                    if(timer)
                    {
                        th.del_timer(timer);
                    }
                }
                else
                {
                    printf("get %d bytes of client data %s from %d\n",ret,users[sockfd].buf,sockfd);
                    if(timer)
                    {    
                        time_t cur = time(NULL);
                        timer->expire = cur +3*TIMESLOT;
                        printf("adjust timer once\n");

                    }
                }
            }
            else
            {
                printf("something else happened\n");
            }
        }
        if(timeout)
        {
            time_handler();
            timeout = 0;
        }
    }
    close(sock);
    close(pipefd[0]);
    close(pipefd[1]);
    delete []users;//???
    return 0;
}

cli.c:

#include"./utili1.h"

int main(int argc,char *argv[])
{
    const char *ip = argv[1];
    int port = atoi(argv[2]);

    struct sockaddr_in addrSer;
    bzero(&addrSer,sizeof(addrSer));
    addrSer.sin_family = AF_INET;
    addrSer.sin_port = htons(port);
    inet_pton(AF_INET,ip ,&addrSer.sin_addr);

    int sock = socket(AF_INET,SOCK_STREAM,0);
    assert(sock>=0);
    
    int ret = connect(sock,(struct sockaddr*)&addrSer,sizeof(addrSer));
    assert(ret>=0);

    char buf[50];


    while(1)
    {
        scanf("%s",buf);
        ret = send(sock,buf,strlen(buf),0);
        if(ret<0)
        {
            printf("errno = %d\n",errno);
            break;
        }
/*        ret = recv(sock,buf,38,MSG_DONTWAIT );
        if(ret!=0)
        {
            printf("%s",buf);
            break;
        }
*/    
    }
/*
    while(1)
    {

        ret = recv(sock,buf,50,0);
        if(ret<0)
        break;
        else if(ret == 0)
        {
            printf("sever close connextion\n");
            break;
        }
        else
        printf("get %d bytes :  %s\n",(int)strlen(buf),buf);
    }
*/
    close(sock);
}

[email protected]:~/sigalarm/time_heap_sigalarm$


相關推薦

時間實現定時

時間堆:將所有定時器中超時最小的一個作為心搏間隔,這樣,一旦心搏函式tick被呼叫,超時時間最小的一個定時器必然到期,我們就可以在tick函式裡處理該定時器,這樣就實現了較為精確的定時. 最小堆很適合這種方案,最小堆的堆頂永遠為最小的元素,這樣每次只要將堆頂的定時器處理,

一個最小簡單定時實現demo

#include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <time.h> #include <unistd.h> #

linux核心設計與實現 —— 定時時間管理(第11章)

核心中的時間概念 硬體為核心提供了一個系統定時器用以計算流逝的時間。系統定時器是一種可程式設計硬體晶片,它能以固定頻率產生中斷。該頻率可以通過程式設計預定,稱作節拍率(tick rate)。該中斷就是所謂的定時器中斷,它所對應的中斷處理程式負責更新系統時間,也

不用寫Windows服務實現定時功能(FluentScheduler )

ace 簡單 要去 job macbook sharp 管理 dia 做到 MacBook Pro 只有四個 USB Type-C 接口是否錯了? 一項新技術的誕生總會對已存在的事物造成沖擊或影響,如果大家都害怕沖擊與影響,那這個世界永遠像現在不變就行了,大家都好好的,待

day27—JavaScript實現定時及其應用案例

scrip tin 定時 定時器對象 延遲 day 方法 fun value 轉行學開發,代碼100天——2018-04-12 JavaScript中定時器有兩種,分別是setInterval和setTimeout;其用法如下: 開啟: setTimeout("fun

利用deadline_timer實現定時Timer

second adl span 停止 deadline timer style set hello 1 // 類似QTimer的定時器 2 class Timer 3 { 4 typedef void(* handler)(); 5 public: 6

springMVC + quartz實現定時(任務排程

首先我們要知道任務排程器(定時器)有幾種,這邊我會寫三種 第一種是基於JDK的本身的一個定時器(優點:簡單,缺點:滿足不了複雜的需求) package com.timer1; import java.util.Date; import java.util.TimerTask;

PHP 使用do while 實現定時功能

<?php require "./config.php"; require "./function/function.php"; header("content-type:text/html;charset=utf-8"); ignore_user_abort();//關閉瀏覽器仍然

Spirng 實現定時

一、自定義applicationContext-schedule.xml, <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans

php 用swoole 實現定時 執行linux指令碼,檢查程序掛了,重啟操作

利用swoole的定時器,每兩秒檢查一下 class Grep  {          const PORT = 9999;     public function port()  &n

基於STM32F103ZET6主控平臺實現定時TIM3的驅動

一個熱愛程式碼的工程師,唯有憑藉雙手不斷敲打,才可以快速提升實力! 本文謹以記錄,日後相忘時再作複習,程式碼沒有貴賤,既來之則安之。 定時器描述:定時器的運用主要是對重灌載值和預分頻的配置,這兩個暫存器配置決定定時器定時的時長,接下來是開啟定時器中斷,當設定的時長溢位便會

Spring定時時間表達式 定時時間表達式:

1. 欄位 允許值 允許的特殊字元    秒 0-59 , - * /    分 0-59 , - * /    小時 0-23 , - * /    日期 1-31 , - * ? / L W C &n

利用快取過期在ASP.NET中實現定時

在B/S結構中要實現定時器(或者說是一個事務)實在不是一件好辦的事。可當你在網上搜索“ASP.NET定時器”的時候,你會發現搜尋結果是如此的多,可這大多數結果中的程式碼健壯性都是那樣的脆弱——沒有考慮諸如IIS程序的自然消亡、IIS程序的故障崩潰、重啟伺服器等等因素。這

在dll裡實現定時功能

一,首先引入“mmsystem”單元。二,啟動定時器:     var        MMTimerID: Integer; // 定時器ID        MMTimerID := timeSetEvent(1000, 0, @TimerProc, 0, TIME_PERI

java中實現定時的四種方法(轉載)

轉載java中實現定時器的方法,記錄方便檢視。package com.wxltsoft.tool; import org.junit.Test; import java.util.Calendar; import java.util.Date; import java.u

java 實現定時修改

package test; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStre

基於Android中實現定時的3種解決方法

在Android開發中,定時器一般有以下3種實現方法:一、採用Handler與執行緒的sleep(long)方法 二、採用Handler的postDelayed(Runnable, long)方法 三、採用Handler與timer及TimerTask結合的方法下面逐一介紹

linux下c/c++例項之六時間測試和定時

一、簡介       Linux中使用sleep會導致程式一直阻塞,無法互動,同時sleep和usleep有時也不精確,在此總結linux下的部分時間操作。 二、詳解 1、程式碼timer.cpp #include <iostream> #include &

Android中實現定時的四種方式

第一種方式利用Timer和TimerTask 1、繼承關係 java.util.Timer 基本方法 schedule 例如: timer.schedule(task, delay,per

實現定時功能的幾種方式

nsrunLoop GCD RAC NsrunLoop NSRunLoop是IOS訊息機制的處理模式 一條執行緒對應一個RunLoop,主執行緒的RunLoop預設已經建立好了, 而子執行緒的需要我們自己手動