服务器设计笔记(1)-----定时器的实现(C++)

很久之前听著名页游服务器主程讲座时,讲到过定时器的实现,基本思路如下(易语言)

       while(true)

       {

             对定时器进行排序。

             for(遍历定时器)

             {

                   if 如果定时器到:

                          callback;

                   else

                           break; 

             } 

             usleep(20);

         }

        按照这个思路,我们继续我们的设计:

1: 首先 定义一个Thread类:

         

/*
 * Thread.h
 *
 *  Created on: Sep 11, 2012
 *      Author: root
 */

#ifndef THREAD_H_
#define THREAD_H_

#include <pthread.h>

class Thread {

public:
    enum THREADSTATE
    {
        IDLE,
        WORK,
        BUSY,
    };

public:

    Thread();

    virtual ~Thread();

    virtual void* run(void) = 0;

    virtual int start(void);

    virtual int cancel(void);

    pthread_t get_pid() const
    {
        return pid;
    }

protected:

    THREADSTATE _thread_state;

private:

    pthread_t pid;

    static void* thread_entry(void* para);
};

#endif /* THREAD_H_ */

        实现代码Thread.cpp:

View
Code

/*
 * Thread.cpp
 *
 *  Created on: Sep 11, 2012
 *      Author: root
 */

#include "Thread.h"

Thread::Thread() {
    // TODO Auto-generated constructor stub

}

Thread::~Thread() {
    // TODO Auto-generated destructor stub
}

void* Thread::thread_entry(void* para)
{
    Thread *pThread = static_cast<Thread *>(para);
    return pThread->run();
}

int Thread::start(void)
{
    if(pthread_create(&pid,0,thread_entry,static_cast<void *>(this)) < 0)
    {
        pthread_detach(this->pid);
        return -1;
    }
    return 0;
}

int Thread::cancel(void)
{
    pthread_cancel(this->pid);
    return 0;
}

 2:定义定时器,和定时器线程:

         TimerThread.h

         

/*
 * Timer.h
 *
 *  Created on: Sep 11, 2012
 *      Author: root
 */

#ifndef TIMER_H_
#define TIMER_H_

#include "Thread.h"
#include <list>

using namespace std;

struct Timer
{

    void *_args;
    int (*_callback)();
    int _interval;
    int leftsecs;
    void open(int interval,int (*callback)())
    {
        _interval = interval * 1000;
        leftsecs = _interval;
        _callback = callback;
    }

    bool operator < (Timer _timer)
    {
        return _timer.leftsecs < this->leftsecs;
    }

    bool operator == (Timer _timer)
    {
        return _timer.leftsecs == this->leftsecs;
    }

};

class TimerThread : public Thread
{

public:

    static TimerThread* _instance;

    static TimerThread* get_instance();

    virtual void* run(void);

    virtual ~TimerThread();

    void Register(Timer _timer);

    void unRegister(Timer _timer);

private:

    TimerThread();

    list<Timer> _timer_list;

};

extern unsigned int get_systime_clock();

#define TIMERMANAGE TimerThread::get_instance()

#endif /* TIMER_H_ */

 

          实现代码:TimerThread.cpp

View
Code

/*
 * Timer.cpp
 *
 *  Created on: Sep 11, 2012
 *      Author: root
 */

#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include "Timer.h"

TimerThread* TimerThread::_instance;

TimerThread::TimerThread()
{

}

TimerThread::~TimerThread()
{

}

void* TimerThread::run(void)
{
    while(true)
    {
        unsigned int start_clock = get_systime_clock();
        this->_timer_list.sort();
        list<Timer>::iterator iter;
        for(iter = this->_timer_list.begin();
                iter != this->_timer_list.end();
                    iter ++)
        {
            iter->leftsecs --;
            if(iter->leftsecs == 0)
            {
                iter->_callback();
                iter->leftsecs = iter->_interval;
            }
        }
        unsigned int end_clock = get_systime_clock();

        usleep(1000 + start_clock - end_clock);
    }
    return (void*)0;
}

void TimerThread::Register(Timer _timer)
{
    this->_timer_list.push_back(_timer);
}

void TimerThread::unRegister(Timer _timer)
{
    this->_timer_list.remove(_timer);
}

TimerThread* TimerThread::get_instance()
{
    if(_instance == NULL)
    {
        _instance = new TimerThread();
    }
    return _instance;
}

unsigned int get_systime_clock()
{
    struct timeval now;
    gettimeofday(&now,NULL);
    return now.tv_sec*1000 + now.tv_usec/1000;
}

          

 3: 测试函数:

View
Code

//============================================================================
// Name        : test.cpp
// Author      : archy
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <string>
#include <stdio.h>
#include <sys/types.h>

#include "Timer.h"

using namespace std;

int handle_timeout()
{
    unsigned int time = get_systime_clock();
    printf("time out,%u\n",time);
    return 0;
}

int main()
{
    Timer _timer;
    _timer.open(1,handle_timeout);
    TIMERMANAGE->Register(_timer);
    TIMERMANAGE->start();
    getchar();
    return 0;
}

       

目前存在的问题:定时不准,主要是由于usleep()之后 ,不能及时醒,这个是因为Linux线程调度引起的。

改进的方向:1. TimerThread 里面的list换成优先队列

                 2. 添加时间纠正,在测试中发现,每次大概慢100us左右,这对于长时间的定时器是致命。

也想听听广大网友的意见,感激不尽。 

时间: 2024-11-03 16:27:37

服务器设计笔记(1)-----定时器的实现(C++)的相关文章

服务器设计笔记(2)-----定时器的实现(C++)

   很久之前听著名页游服务器主程讲座时,讲到过定时器的实现,基本思路如下(易语言)        while(true)        {              对定时器进行排序.              for(遍历定时器)              {                    if 如果定时器到:                           callback;                    else                           

服务器设计笔记(4)-----客户端通信模块

   整个底层通信模块修改过很多次,因为首次使用epoll,在其中遇见了很多问题,最终设计成下面的方式:        1: 对于epoll中EPOLLOUT事件的使用,因为频繁的调用send()函数,系统会在内核模式和用户模式之间切换太多消耗太大,所以最终启用了定时器模式,比如以50ms为间隔,定时的遍历所有的ClientPlayer 去发送 OutStream 里面的数据.    2: 最开始使用玩家的id 对应每个玩家的ClientPlayer的,在玩家没有进入的时候 使用玩家的账号名:

服务器设计笔记(5)-----守护进程

守护进程的定义:        通常说的Daemon进程,是Linux中的后台服务进程.它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.这事百科对此的解释,在游戏服务器里面也有守护进程,特点大概也类似. 游戏守护进程的定义:        游戏服务器里面的守护进程大概完成的职责有这些.1,负责多个进程的启动:2,在进程挂掉的时候负责启动相应的进程:3,可以查询程序运行的情况等等. 游戏守护进程的原理:       设计守护进程为父进程,验证进程,聊天

服务器设计笔记(1)-----消息的封装

    消息的封装方式有多中,比如xml,json等,但是我依然觉得使用拼数据的方式最简单,也最节省带宽.比如我们处理一个逻辑就可以这样处理了:     int cast_net(MessageBlock &mb)     {         int  area_id,lvl;         mv >> area >> lvl;         //逻辑处理         //....         MessageBlock re_mb;         re_mb

服务器设计笔记(5)-----分享几个线程安全的容器

    首先是 队列 PipeList    /* * PipeList.h * * Created on: Aug 28, 2012 * Author: archy_yu */ #ifndef PIPELIST_H_ #define PIPELIST_H_ #include <list> #include "Mutex.h" #include "GameUtil.h" template <class CObject> class PipeL

服务器设计笔记(3)-----消息队列

    摘抄的一篇文章,故拿出来记录下,下篇博客把解决代码分享出来.感谢这篇文章的原作者,解决了棘手的问题.       我们所能想到的最简单的消息队列可能就是使用stl的list来实现了,即消息队列内部维护一个list和一个互斥锁,putMessage时将message加入到队列尾,getMessage时从队列头取一个message返回,同时在getMessage和putMessage之前都要求先获取锁资源. 实现虽然简单,但功能是绝对满足需求的,只是性能上可能稍稍有些不尽如人意.其最大的问题

动态网页设计笔记

动态网页设计笔记    JavaScript.ASP.ASP.Net.JSP笔记   JavaScript ASP.net ASP 1.基本控件的使用6.客户端脚本的基本对象    ***41.常用的Javascript内建类的方法  ***2.让TextArea自动换行3.让TextArea支持Table键4.复制数据到剪贴板5.得到当前选中的文本7.保护自己编写的HTML和脚本的方法8.IE地址栏前换成自己的图标9.可以在收藏夹中显示出你的图标10.关闭输入法11.直接查看源代码12.在Ja

日志服务器设计

日志服务器设计(草稿)   我的想方式实现一个Log服务器,然后把所有日志推向这个服务器.   同时兼容现有的   rsyslog log4J, log4cpp... 可以通过TCP/UDP/和管道,向日志服务器抛日志. 日志服务器,采用多线程处理,然后放入列队.另一个进程从列队取日志,然后进行过滤,通过特征库匹配. 例如: 放行,抛弃,报警(通过email和手机短信) 放行数据将通过存储引擎,进行日志保存,可以进入数据库,文件.如果是文件通过gzip管道流,在做日志切割. 客户端 客户端是一个

IBM展示全新服务器设计架构EX5的新款服务器产品

IBM于本周二在德国汉诺威举行的http://www.aliyun.com/zixun/aggregation/14435.html">CeBIT trade show上展示了采用了全新服务器设计架构EX5的新款System x和BladeCenter服务器产品,新产品在削减数据中心能耗成本的同时极大提升应用的性能表现. EX5服务器的架构和传统x86服务器架构有所区别.传统的x86架构将处理器和内存是绑在一起的,而采用了IBM第五代X架构的EX5服务器将内存从处理器中分离出来,自成一体.