`
sony-soft
  • 浏览: 1019393 次
文章分类
社区版块
存档分类
最新评论

linux 延时函数几个资料

 
阅读更多

linux 延时函数几个资料

转自
http://blog.ednchina.com/qiu1123/251065/Message.aspx

一、基础知识
1、时间类型。
Linux下常用的时间类型有4个:time_t,struct timeval,struct timespec,struct tm。
(1)time_t是一个长整型,一般用来表示用1970年以来的秒数。
(2)Struct timeval有两个成员,一个是秒,一个是微妙。

linux 延时函数几个资料 - mervyn807 - mervyn807的博客structtimeval{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
longtv_sec;/*seconds*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
longtv_usec;/*microseconds*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}
;

(3)struct timespec有两个成员,一个是秒,一个是纳秒。

linux 延时函数几个资料 - mervyn807 - mervyn807的博客structtimespec{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客time_ttv_sec;
/*seconds*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
longtv_nsec;/*nanoseconds*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}
;

(4)struct tm是直观意义上的时间表示方法:

linux 延时函数几个资料 - mervyn807 - mervyn807的博客structtm{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
inttm_sec;/*seconds*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
inttm_min;/*minutes*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
inttm_hour;/*hours*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
inttm_mday;/*dayofthemonth*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
inttm_mon;/*month*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
inttm_year;/*year*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
inttm_wday;/*dayoftheweek*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
inttm_yday;/*dayintheyear*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
inttm_isdst;/*daylightsavingtime*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}
;

2、时间操作
(1)时间格式间的转换函数
主要是 time_t、struct tm、时间的字符串格式之间的转换。看下面的函数参数类型以及返回值类型:

linux 延时函数几个资料 - mervyn807 - mervyn807的博客char*asctime(conststructtm*tm);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
char*ctime(consttime_t*timep);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客structtm
*gmtime(consttime_t*timep);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客structtm
*localtime(consttime_t*timep);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客time_tmktime(structtm
*tm);

gmtime和localtime的参数以及返回值类型相同,区别是前者返回的格林威治标准时间,后者是当地时间。
(2)获取时间函数
两个函数,获取的时间类型看原型就知道了:

linux 延时函数几个资料 - mervyn807 - mervyn807的博客time_ttime(time_t*t);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
intgettimeofday(structtimeval*tv,structtimezone*tz);

前者获取time_t类型,后者获取struct timeval类型,因为类型的缘故,前者只能精确到秒,后者可以精确到微秒。
二、延迟函数
主要的延迟函数有:sleep(),usleep(),nanosleep(),select(),pselect().

linux 延时函数几个资料 - mervyn807 - mervyn807的博客unsignedintsleep(unsignedintseconds);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidusleep(unsignedlongusec);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
intnanosleep(conststructtimespec*req,structtimespec*rem);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
intselect(intn,fd_set*readfds,fd_set*writefds,fd_set*exceptfds,structtimeval*timeout);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
intpselect(intn,fd_set*readfds,fd_set*writefds,fd_set*exceptfds,conststructtimespec*timeout,constsigset_t*sigmask);

alarm函数是信号方式的延迟,这种方式不直观,这里不说了。
仅通过函数原型中时间参数类型,可以猜测sleep可以精确到秒级,usleep/select可以精确到微妙级,nanosleep和pselect可以精确到纳秒级。
而实际实现中,linux上的nanosleep和alarm相同,都是基于内核时钟机制实现,受linux内核时钟实现的影响,并不能达到纳秒级的精度,man nanosleep也可以看到这个说明,man里给出的精度是:Linux/i386上是10 ms ,Linux/Alpha上是1ms。
这里有一篇文章http://blog.csdn.net/zhoujunyi/archive/2007/03/30/1546330.aspx,测试了不同延迟函数之间的精确度。文章给出的结论是linux上精度最高的是select,10ms级别。我在本机器测试select和pselect相当,都达到了1ms级的精度,精度高于文章中给出的10ms,sleep在秒级以上和usleep/nanosleep相当。下面贴下我机器上1ms时候的测试结果,其他不贴了:

linux 延时函数几个资料 - mervyn807 - mervyn807的博客sleep10000-1000
linux 延时函数几个资料 - mervyn807 - mervyn807的博客usleep
100029741974
linux 延时函数几个资料 - mervyn807 - mervyn807的博客nanosleep
100029901990
linux 延时函数几个资料 - mervyn807 - mervyn807的博客select
1000991-9
linux 延时函数几个资料 - mervyn807 - mervyn807的博客pselect
1000990-10
linux 延时函数几个资料 - mervyn807 - mervyn807的博客gettimeofday
100010000

而使用gettimeofday循环不停检测时间,可精确微秒级,不过不适宜用来做定时器模块。
因此后面的定时期模块将选择select为延迟函数。
三、定时器模块需求以及实现概述
1、需求。从实现结果的角度说来,需求就是最终的使用方式。呵呵,不详细描述需求了,先直接给出我实现的CTimer类的三个主要接口:

linux 延时函数几个资料 - mervyn807 - mervyn807的博客ClassCTimer{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客Public:
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimer(unsigned
intvinterval,void(*vfunc)(CTimer*,void*),void*vdata,TimerTypevtype);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidstart();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidstop();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidreset(unsignedintvinterval);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}
;

使用定时器模块的步骤如下:
(1)实例化一个CTimer,参数的含义依次是:vinterval间隔时间(单位ms),vfunc是时间到回调的函数,vdata回调函数使用的参数,vtype定时器的类型,分一次型和循环型两种。
(2)调用start方法。
(3)必要的时候调用stop和reset。
2、实现。简单描述下定时器模块的实现,有一个manager单例类保存所有CTimer对象,开启一线程运行延迟函数,每次延迟间隔到,扫描保存CTimer的容器,对每个CTimer对象执行减少时间操作,减少到0则执行回调函数。对一次性CTimer,超时则从容器中删除,循环型的将间隔时间重置,不从容器中移除。
CTimer的start执行将对象插入到manager容器中操作;stop执行将对象从manager容器中删除的操作;reset执行先删除,重置间隔,然后再放到容器中,reset不改变CTimer的定时器类型属性。
四、定时器模块的数据结构选择
Manager类的容器要频繁进行的操作涉及插入、删除、查询等。
误区:(1)简单看,好象该容器要是有序的,方便插入删除等,貌似红黑树比较合适。其实不然,插入删除操作的频率很低,最频繁的还是每次时延到,对容器的扫描并做时间减少操作,红黑树在做顺序扫描相对链表并没什么优势。
(2)插入的时候依照顺序链表的方式插入到合适的位置保持排序,以保证超时的对象都在链表的头端。其实这也是没必要的,每次时延到,对每一个对象都要做时间减少操作,因此不管是有序还是无序,都是一次扫描就执行完下面操作:减少时间、判断是否超时,是则执行回调,继续判断是什么类型,一次型的则执行完就移除,循环型则执行完直接重置间隔就可。
因此,只需要能快速插入头、删除结点、遍历就好。我的实现直接使用BSD内核中的数据结构LIST,插入头、删除时间复杂度都是1,遍历就不说了。linux下/usr/include/sys下有头文件queue.h里也有LIST结构以及操作的定义。貌似linux下的少了遍历宏:

linux 延时函数几个资料 - mervyn807 - mervyn807的博客#defineLIST_FOREACH(var,head,field)\
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
for((var)=LIST_FIRST(head);\
linux 延时函数几个资料 - mervyn807 - mervyn807的博客(var)
!=LIST_END(head);\
linux 延时函数几个资料 - mervyn807 - mervyn807的博客(var)
=LIST_NEXT(var,field))

五、详细实现
这里帖出主要的代码,请重点关注CTimerManager:: process方法,不再详细说了。需要详细的全部代码,可来信索取,整体代码很简单,就两个类。

linux 延时函数几个资料 - mervyn807 - mervyn807的博客classCTimer
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客friend
classCTimerManager;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
public:
linux 延时函数几个资料 - mervyn807 - mervyn807的博客typedef
enum
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客TIMER_IDLE
=0,//start前以及手动调用stop后的状态
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
TIMER_ALIVE,//在manager的list里时候的状态
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
TIMER_TIMEOUT//超时后被移除的状态,循环型的没有
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
}
TimerState;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客typedef
enum
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客TIMER_ONCE
=0,//一次型
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
TIMER_CIRCLE//循环型
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
}
TimerType;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimer(unsigned
intvinterval,void(*vfunc)(CTimer*,void*),void*vdata,TimerTypevtype);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidstart();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidstop();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidreset(unsignedintvinterval);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
~CTimer();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
private:
linux 延时函数几个资料 - mervyn807 - mervyn807的博客unsigned
intid_;//测试用
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
unsignedintm_interval;//间隔,不变
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
unsignedintm_counter;//开始设置为interval,随延迟时间到,减少
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
TimerStatem_state;//状态
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
TimerTypem_type;//类型
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
void(*m_func)(CTimer*,void*);//回调函数
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
void*m_data;//回调函数参数
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
LIST_ENTRY(CTimer)entry_;//LIST的使用方式
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
}
;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
/*构造函数*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimer::CTimer(unsigned
intvinterval,void(*vfunc)(CTimer*,void*),void*vdata,TimerTypevtype):
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
linux 延时函数几个资料 - mervyn807 - mervyn807的博客m_interval(vinterval),m_counter(vinterval),
linux 延时函数几个资料 - mervyn807 - mervyn807的博客m_state(TIMER_IDLE),m_type(vtype),
linux 延时函数几个资料 - mervyn807 - mervyn807的博客m_func(vfunc),m_data(vdata)
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{}
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
/*开始定时器*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidCTimer::start()
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimerManager::instance()
->add_timer(this);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}

linux 延时函数几个资料 - mervyn807 - mervyn807的博客
/*停止定时器*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidCTimer::stop()
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimerManager::instance()
->remove_timer(this);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}

linux 延时函数几个资料 - mervyn807 - mervyn807的博客
/*reset定时器*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidCTimer::reset(unsignedintvinterval)
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimerManager::instance()
->remove_timer(this);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客m_counter
=m_interval=vinterval;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimerManager::instance()
->add_timer(this);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}

linux 延时函数几个资料 - mervyn807 - mervyn807的博客
/*析构函数,stop操作不能省略,避免delete前忘记stop*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimer::
~CTimer()
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
if(m_state==TIMER_ALIVE)
linux 延时函数几个资料 - mervyn807 - mervyn807的博客stop();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}

CTimerManager的:

linux 延时函数几个资料 - mervyn807 - mervyn807的博客classCTimerManager
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
public:
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
linux 延时函数几个资料 - mervyn807 - mervyn807的博客typedef
enum
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客TIMER_MANAGER_STOP
=0,
linux 延时函数几个资料 - mervyn807 - mervyn807的博客TIMER_MANAGER_START
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}
TimerManagerState;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
staticCTimerManager*instance();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidadd_timer(CTimer*vtimer);//线程安全的add
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidremove_timer(CTimer*vtimer);//线程安全的remove
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidstart();//开始process线程
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidstop();//停止process线程
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voiddump();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
protected:
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
staticvoid*process(void*);//实际的定时器时间延迟线程
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
private:
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidadd_timer_(CTimer*vtimer);//非线程安全的add
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidremove_timer_(CTimer*vtimer);//非线程安全的remove
linux 延时函数几个资料 - mervyn807 - mervyn807的博客

linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimerManager();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
staticpthread_mutex_tm_mutex;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
staticCTimerManager*m_instance;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
linux 延时函数几个资料 - mervyn807 - mervyn807的博客TimerManagerStatem_state;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客LIST_HEAD(,CTimer)list_;
//LIST使用方式
linux 延时函数几个资料 - mervyn807 - mervyn807的博客

linux 延时函数几个资料 - mervyn807 - mervyn807的博客
staticunsignedintmark;//测试,配合dump
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
}
;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
/*singlton的double-check实现*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimerManager
*CTimerManager::instance()
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
if(m_instance==NULL)
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客pthread_mutex_lock(
&m_mutex);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
if(m_instance==NULL)
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客m_instance
=newCTimerManager();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}

linux 延时函数几个资料 - mervyn807 - mervyn807的博客pthread_mutex_unlock(
&m_mutex);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}

linux 延时函数几个资料 - mervyn807 - mervyn807的博客
returnm_instance;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}

linux 延时函数几个资料 - mervyn807 - mervyn807的博客
/*process必须static,不能操作非static属性,因此传递this指针*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidCTimerManager::start()
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
if(m_state==TIMER_MANAGER_STOP){
linux 延时函数几个资料 - mervyn807 - mervyn807的博客m_state
=TIMER_MANAGER_START;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客pthread_tpid;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客pthread_create(
&pid,0,process,this);
}
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}

linux 延时函数几个资料 - mervyn807 - mervyn807的博客
/*定时器模块延迟时间线程*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
void*CTimerManager::process(void*arg)
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客pthread_detach(pthread_self());
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimerManager
*manage=(CTimerManager*)arg;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimer
*item;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客structtimevalstart,end;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客unsigned
intdelay;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
linux 延时函数几个资料 - mervyn807 - mervyn807的博客structtimevaltm;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客gettimeofday(
&end,0);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
/*使用状态控制线程运行,进而容易实现stop,也可以使用pthread_cancel粗暴的停止,需要考虑暂停点等问题*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
while(manage->m_state==TIMER_MANAGER_START)
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客tm.tv_sec
=0;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客tm.tv_usec
=DEFULT_INTERVAL*1000;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客start.tv_sec
=end.tv_sec;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客start.tv_usec
=end.tv_usec;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
/*不同系统的延迟函数精度不同,如果需要替换为其他延迟函数,这附近修改下就好*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
while(select(0,0,0,0,&tm)<0&&errno==EINTR);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客gettimeofday(
&end,0);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
linux 延时函数几个资料 - mervyn807 - mervyn807的博客delay
=(end.tv_sec-start.tv_sec)*1000+(end.tv_usec-start.tv_usec)/1000;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客pthread_mutex_lock(
&manage->m_mutex);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
linux 延时函数几个资料 - mervyn807 - mervyn807的博客LIST_FOREACH(item,
&(manage->list_),entry_)
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客item
->m_counter<delay?item->m_counter=0:item->m_counter-=delay;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
if(item->m_counter==0)
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
if(item->m_func)
linux 延时函数几个资料 - mervyn807 - mervyn807的博客item
->m_func(item,item->m_data);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
if(item->m_type==CTimer::TIMER_ONCE)
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
/*一次型的,超时,移除,并状态CTimer::TIMER_TIMEOUT*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客manage
->remove_timer_(item);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客item
->m_state=CTimer::TIMER_TIMEOUT;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}

linux 延时函数几个资料 - mervyn807 - mervyn807的博客
elseif(item->m_type==CTimer::TIMER_CIRCLE)
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
/*循环型的,重置counter就好*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客item
->m_counter=item->m_interval;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}

linux 延时函数几个资料 - mervyn807 - mervyn807的博客}

linux 延时函数几个资料 - mervyn807 - mervyn807的博客}

linux 延时函数几个资料 - mervyn807 - mervyn807的博客
linux 延时函数几个资料 - mervyn807 - mervyn807的博客pthread_mutex_unlock(
&manage->m_mutex);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}

linux 延时函数几个资料 - mervyn807 - mervyn807的博客}



六、讨论
(1)精度问题。精度高,实时性高,但要求select等待的时间缩短,进而增加对LIST结构的扫描操作。精度低,实时性差,但会增加定时器线程的睡眠时间,减少对cpu的占用。一般的应用系统,应该尽量降低精度,避免不必要的扫描,对具体系统可考察所用到的所有定时器的实际间隔,在允许的情况下,尽量降低精度,可通过修改代码中的宏实现。为了降低定时器线程对cpu的占有时间,甚有更为粗犷型的定时器模块实现为将延迟时间取list中最小的那个间隔,保证每次延迟时间到都有回调。
(2)加锁区域问题。本文中的定时器模块实现,将定时器对象的时间减少以及函数回调的执行等再同一个临界区内执行,而有的定时器模块实现是在加锁区域执行“时间减少”操作,将减少到0的对象放到另一个超时链表中,解锁后再单独扫描超时链表执行回调操作。很明显,后者缩短了加锁时间,能及时响应其他的线程的定时器对象的start以及stop操作。但是后者对定时器操作的时序性有误差,直观反应就是可能在定时器执行了stop操作以后,仍然会有超时回调发生,特别是回调参数是指针的情况,可能引起难以发现的bug,增加调试困难。在衡量两者的利弊后,本文采用延长加锁时间以保证操作的时序性。因此,在实际的使用,回调函数应尽快返回,另一方面,尽量减少系统内使用的定时器数目,这个主要原因是延迟时间到要扫描LIST,哪种方式都避免不了。

七、使用示例

linux 延时函数几个资料 - mervyn807 - mervyn807的博客#include"timer_manager.h"
linux 延时函数几个资料 - mervyn807 - mervyn807的博客#include
<stdio.h>
linux 延时函数几个资料 - mervyn807 - mervyn807的博客#include
<unistd.h>
linux 延时函数几个资料 - mervyn807 - mervyn807的博客#include
<stdlib.h>
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
voidfunc(CTimer*timer,void*data)
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客printf(
"hi,%d\n",(int
)(data));
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}

linux 延时函数几个资料 - mervyn807 - mervyn807的博客
/*随便写的,凑合着看吧。没有CTimerManager::instance()->stop();也没new对象。定时器对象可多次start和stop,使用上对暴露的接口没有任何的契约式限制,可随意调用*/
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
intmain()
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
{
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimerManager::instance()
->start();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimera(
1000,func,(void*)1,CTimer::TIMER_CIRCLE);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimera1(
2000,func,(void*)11,CTimer::TIMER_ONCE);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimera2(
3000,func,(void*)12,CTimer::TIMER_ONCE);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimera3(
1000,func,(void*)13,CTimer::TIMER_ONCE);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
linux 延时函数几个资料 - mervyn807 - mervyn807的博客a.start();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客a1.start();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客a2.start();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客a3.start();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客a.start();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客a1.start();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客a2.start();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客a3.start();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
linux 延时函数几个资料 - mervyn807 - mervyn807的博客sleep(
1);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimerManager::instance()
->dump();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客sleep(
1);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客CTimerManager::instance()
->dump();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客a.reset(
2000);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客a1.stop();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客a3.stop();
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
linux 延时函数几个资料 - mervyn807 - mervyn807的博客sleep(
10);
linux 延时函数几个资料 - mervyn807 - mervyn807的博客
return0
;
linux 延时函数几个资料 - mervyn807 - mervyn807的博客}

分享到:
评论

相关推荐

    多任务操作系统中的延时操作应该注意的事项

    Linux等多任务操作系统中使用延时函数要特别注意以下几点:  (1)应用层和内核层的延时函数是不能混用的。因为,内核层的延时函数在调用过程中是不会发生任务切换的延时是精确的,而应用层的延时函数在延时函数...

    linux内核驱动学习

    当一个设备驱动需要处理硬件的延迟(latency潜伏期), 涉及到的延时通常最多几个毫秒,在这个情况下, 不应依靠时钟嘀哒,而是内核函数

    linux系统编程之线程.zip

    【练习】:循环创建多个线程,每个线程打印自己是第几个被创建的线程。(类似于进程循环创建子进程) 【more_pthrd.c】 拓展思考:将pthread_create函数参4修改为(void *)&i, 将线程主函数内改...

    ARM_Linux启动分析.pdf

    在一般的系统实现中,都使用了2、3、4、5几个级别,在 Redhat系统中,2表示无NFS支持的多用户模式,3表示完全多用户模式(也是最常用的级别),4保留给用户自定义,5表示XDM图形登录方式。7- 9级别也是可以使用的,...

    linux设备驱动程序第三版

    1. Linux 设备驱动第三版 .................................................................................................................... 5 2. 第 1 章 设备驱动简介 ....................................

    Linux多线程服务端编程:使用muduo C++网络库

    《Linux多线程服务端编程:使用muduo C++网络库》主要讲述采用现代C++在x86-64 Linux上编写多线程TCP网络服务程序的主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即one loop per thread。...

    嵌入式操作系统ucos的学习要点复习要点.doc

    C/OS-Ⅱ操作系统初始化所须完成的的五件事:初始化几个重要的全局变量、数组OSTCBPrioTbl[ ]、就绪表、五个链表(空任务控制块、空事件控制块、空队列控制块、空信号量集标志组、空内存控制块)、创建空闲任务。...

    coreutils-8.32.tar.gz

    把一个文件按照给定的模式或者行号分成几块 cut 从指定的文件中提取特定的列送到标准输出 date 以特定的格式显示当前时间,或者设置系统日期 dd 以可选块长度复制文件,默认情况下从标准输入设备输出到标准...

    vc++ 应用源码包_5

    演示了OpenG的使用方法,内含几个实例,一个实例就3个文件。 p2p vb实例。 p2p+technology文档。 P2P视频技术源码(含开发文档) PcShare 内含远程控制、进程管理、文件操作、视频控制、注册表操作、客户端...

    java开源包6

    Chronicle 是一个超低延迟、高吞吐、持久化的消息和事件驱动的内存数据库,延迟只有16纳秒以及支持每秒钟 500-2000 万消息/记录。 google-api-translate-java(Java 语言对Google翻译引擎的封装类库) 语音识别程序 ...

    grub4dos-V0.4.6a-2017-02-04更新

    延迟[delay]:序列图像之间的延迟。单位是滴答,即1/18.2秒。 序列数[last_num]:序列图像总数(2位数,从1开始计数)。 偏移[x]、[y]:图像偏移,单位像素。 起始图像文件 START_FILE 命名规则:*n.??? n: 1-9 ...

    uboott移植实验手册及技术文档

    nand_init()函数在两个文件中实现。其调用与 CFG_NAND_LEGACY 宏有 关,如果没有定义这个宏,系统调用 drivers/nand/nand.c 中的 nand_init();否则调用自己在 本文件中的 nand_init()函数,本例使用后者。fs2410.c...

    vc++ 应用源码包_1

    演示了OpenG的使用方法,内含几个实例,一个实例就3个文件。 p2p vb实例。 p2p+technology文档。 P2P视频技术源码(含开发文档) PcShare 内含远程控制、进程管理、文件操作、视频控制、注册表操作、客户端...

    vc++ 应用源码包_2

    演示了OpenG的使用方法,内含几个实例,一个实例就3个文件。 p2p vb实例。 p2p+technology文档。 P2P视频技术源码(含开发文档) PcShare 内含远程控制、进程管理、文件操作、视频控制、注册表操作、客户端...

    vc++ 应用源码包_6

    演示了OpenG的使用方法,内含几个实例,一个实例就3个文件。 p2p vb实例。 p2p+technology文档。 P2P视频技术源码(含开发文档) PcShare 内含远程控制、进程管理、文件操作、视频控制、注册表操作、客户端...

    JAVA上百实例源码以及开源项目源代码

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    vc++ 应用源码包_3

    演示了OpenG的使用方法,内含几个实例,一个实例就3个文件。 p2p vb实例。 p2p+technology文档。 P2P视频技术源码(含开发文档) PcShare 内含远程控制、进程管理、文件操作、视频控制、注册表操作、客户端...

    c语言编写单片机技巧

    项目相当繁多,以HOLTEK-p.htm" target="_blank" title="HOLTEK货源和PDF资料"&gt;HOLTEK产品为例最主要的几项如下: &#61548; 接续性测试:检测每一根I/OPIN内接的保护用二极管是否功能无误。 &#61548; 功能测试...

    JAVA上百实例源码以及开源项目

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

Global site tag (gtag.js) - Google Analytics