• 服务器架构设计1


    说到服务器,通常可以想象都是一个while(1)无限循环,当某种条件触发之后,则跳出循环。

    然而,有些时候,则需要服务器针对某些ses,周期性的执行特定操作,如何实现呢。

    一个简单的方法就是,建立session的node list,节点信息包括(time,ses私有变量,回调函数,执行周期interval),主线程周期性的访问这个node list,如果时间条件满足,执行回调函数。


    构造了一个简单node list,便于说明。

    inline uint64_t get_current_clock(void)
    {
        struct timespec tp;
        clock_gettime(CLOCK_MONOTONIC, &tp);
        return (uint64_t)tp.tv_sec * 1e3 + (uint64_t)(tp.tv_nsec / 1e6);
    }
    
    static void heap_insert_helper(timer_event_t* heap[], uint32_t idx)
    {
        if(idx <= 0) {
            return;
        }
        uint32_t p = (idx - 1) >> 1;
        if(heap[p]->time <= heap[idx]->time) {
            return;
        } else {
            timer_event_t* tmp = heap[p];
            heap[p] = heap[idx];
            heap[idx] = tmp;
            heap_insert_helper(heap, p);
        }
    }
    
    static void event_heap_insert(timer_ctx_t* ctx, timer_event_t* evt)
    {
        timer_event_t** heap = ctx->heap;
        uint32_t idx = ctx->nevts++;
        heap[idx] = evt;
        heap_insert_helper(heap, idx);
    }
    
    static void heap_del_helper(timer_event_t* heap[], uint32_t nevts, uint32_t idx)
    {
        if(idx >= nevts) {
            return;
        }
    
        uint32_t lchild = idx * 2 + 1;
        uint32_t rchild = idx * 2 + 2;
        uint32_t i = idx;
    
        if(lchild < nevts && (heap[i]->time > heap[lchild]->time)) {
            i = lchild;
        }
    
        if(rchild < nevts && (heap[i]->time > heap[rchild]->time)) {
            i = rchild;
        }
        
        if(i != idx) {
            timer_event_t* tmp = heap[i];
            heap[i] = heap[idx];
            heap[idx] = tmp;
            heap_del_helper(heap, nevts, i);
        }
    }
    
    static timer_event_t* event_heap_pop(timer_ctx_t* ctx)
    {
        timer_event_t* evt = ctx->heap[0];
        ctx->heap[0] = ctx->heap[--ctx->nevts];
        heap_del_helper(ctx->heap, ctx->nevts, 0);
        return evt;
    }
    
    static void
    event_re_enqueue(timer_ctx_t* ctx, timer_event_t* evt)
    {
        if(evt->enable && evt->interval > 0) {
            evt->time += evt->interval;
            if(evt->count > 0) {
                evt->count--;
                if(evt->count == 0) {
                    evt->interval = 0;
                }
            }
            event_heap_insert(ctx, evt);
        } else {
            mpool_put(evt);
        }
    }
    
    void timer_run(timer_ctx_t *ctx)
    {
        while(ctx->nevts > 0 
              && ctx->heap[0]->time <= get_current_clock()) {
            timer_event_t *evt = event_heap_pop(ctx);
            if(evt->enable && evt->cb) {
                evt->cb(evt->data);
            }
            event_re_enqueue(ctx, evt);
        }
    }
    
    timer_ctx_t* timer_init(timer_ctx_t* ctx)
    {
        if(!ctx) {
            return NULL;
        }
    
        memset(ctx, 0, sizeof(timer_ctx_t));
    
        //make sure mpool is large enough
        ctx->mpool = mpool_calloc(MAX_EVENT_COUNT, sizeof(timer_event_t));
    //    ctx->mpool = mpool_init(sizeof(timer_event_t), 
    //            (sizeof(timer_event_t) + sizeof(void*)) * MAX_EVENT_COUNT + 512, 
    //            NULL);
    
        if(!ctx->mpool) {
            goto error;
        }
    
        return ctx;
    
    error:
        mpool_cleanup(ctx->mpool);
        return NULL;
    }
    
    void timer_cleanup(timer_ctx_t *ctx) 
    {
    
        if(!ctx) {
            return;
        }
        mpool_cleanup(ctx->mpool);
        ctx->mpool = NULL;
    }
    
    int 
    timer_register(
        timer_ctx_t *ctx, 
        timer_cb_t cb, 
        void* data, 
        uint32_t delay, 
        uint32_t interval, 
        uint32_t count)
    {
        timer_event_t *evt = NULL;
        if(ctx->nevts >= MAX_EVENT_COUNT) {
            goto err;
        }
    
        evt = (timer_event_t*)mpool_get(ctx->mpool);
        if(!evt) {
            goto err;
        }
        memset(evt, 0, sizeof(timer_event_t));
    
        int idx = mpool_get_idx(ctx->mpool, evt);
        if(idx < 0) {
            goto err;
        }
    
        evt->id = idx;
        evt->time = get_current_clock() + delay;
        evt->cb = cb;
        evt->data = data;
        evt->interval = interval;
        evt->count = count;
        evt->enable = 1;
    
        event_heap_insert(ctx, evt);
        
        return idx;
    
    err:
        if(evt) {
            mpool_put(evt);
        }    
        return -1;
    }
    
    void timer_cancel(timer_ctx_t *ctx, int id)
    {
        timer_event_t *evt = mpool_get_by_idx(ctx->mpool, id);
        if(evt) {
            evt->enable = 0;
        }
    }


  • 相关阅读:
    Activity的活动Menu和上下文Menu使用示例
    drawable之scale and rotate代码示例
    密度无关和缩放比例无关定义
    [前端优化]使用Combres合并对js、css文件的请求
    不同版本的SQL Server之间数据导出导入的方法及性能比较
    SqlBulkCopy加了事务真的会变快吗?
    ASP.NET Web Forms 4.5的新特性(二):针对HTML5的更新和Unobtrusive Validation
    MVC3缓存之一:使用页面缓存
    MVC3缓存之三:MVC3中的局部缓存(Partial Page)
    ASP.NET Web Forms 4.5的新特性(三):Model Binding
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3230813.html
Copyright © 2020-2023  润新知