代码改变世界

简析LIVE555中的延时队列

2017-11-30 20:21  nigaopeng  阅读(989)  评论(0编辑  收藏  举报

最近在看LIVE555的源码,感觉其中的延时队列写的不错,于是就总结一下。
首先描述一下LIVE555中的延时队列的设计理念。首先,如下图,A,B,C分别为时间轴上的三个事件点,而head表示当前时间点。

    假如我们要描述一个事件发生的时间,可以有两种方法:一种方法直接描述事件发生的绝对时间;另一种方法则是可以描述和另一事件发生的相对时间。而LIVE555中采用的就是后者。在LIVE555中,首先将所有的事件点以发生时间的先后进行排序,然后每个事件对应的时间都是相对于前一事件发生的时间差。比如B事件中存储的时间就是A事件触发后,再去触发B事件所需要的时间。这样,我们每次去查询这个队列中是否有事件被触发的时候,就只需要查询整个队列中的第一个事件就可以了。
     然后就是LIVE555中的实现方法了。整个延时队列是用DelayQueue这个类实现的,而它的基类DelayQueueEntry就是用来描述每个事件节点的。在DelayQueueEntry中的主要成员有以下几个:fDelayTimeRemaining表示的就是与前一事件之间的时间差;fNext和fPrev就是指向时间轴上的下一个事件和前一个事件的指针;ftoken表示当前节点的标识;handleTimeout就是事件超时后的处理方法。
     而DelayQueue类里描述的则是具体的实现方法。首先是一些对这个队列进行的基本操作:addEntry实现的是在队列中增加事件节点;removeEntry实现的是在队列中删除某事件节点;updateEntry实现的则是更新某事件的触发时间;而findEntryByToken则是根据节点的标识查找相应的事件。在此类中最常用的方法应该是synchronize,它实现的就是将整个事件队列和当前系统时间进行同步,检测有无事件已经被触发,如果触发并调用handleAlarm方法对相应事件进行处理。而属性fLastSyncTime表示的就是上次同步的系统时间,其实一般情况下,方法synchronize的实现方法其实就是简单地把队列上第一个事件节点存储的时间差减去当前系统时间和上次同步时间的差。
     基本的实现方法应该就这些,如果大家对这个延时队列感兴趣的话,可以去阅读LIVE555的源码。

 


 

     live555本身是一个单进程、单线程的服务器,但是它能够完美的让多个客户端同时连接,除了使用select并发编程以外,延时队列是很重要的手段。

     当连接一个客户端,进行视频帧传输的时候,是不能持续进行传输的,因为如果持续传输的话会占满整个线程,这样的话新的客户端便无法进行连接了,所以当传送一帧视频流的最后并不会马上再传送下一帧,而是调用scheduleDelayedTask()函数将传送下一帧的工作加入到延时队列里。这个步骤在函数sendPacketIfNecessary()中进行。下面是scheduleDelayedTask()函数的代码:

复制代码
TaskToken BasicTaskScheduler0::scheduleDelayedTask(int64_t microseconds,
                         TaskFunc* proc,
                         void* clientData) {
  if (microseconds < 0) microseconds = 0;
  DelayInterval timeToDelay((long)(microseconds/1000000), (long)(microseconds%1000000));
  AlarmHandler* alarmHandler = new AlarmHandler(proc, clientData, timeToDelay);
  fDelayQueue.addEntry(alarmHandler);

  return (void*)(alarmHandler->token());
}
复制代码

     加入到延时队列之后,需要时刻主动去延时队列查询有没有超时的任务,这个调用操作在SingleStep()函数中完成,SingleStep()最后有如下代码:

  // Also handle any delayed event that may have come due.
  fDelayQueue.handleAlarm();

     就是在这个调用更新延时队列,然后查询有没有超时的任务进行执行。主要调用的函数有removeEntry()(删除延时队列中的节点),synchronize()(同步队列中节点的剩余时间),handleTimeout()(执行超时节点的任务)。

原文链接:https://www.cnblogs.com/nightwatcher/archive/2011/04/10/2011158.html

原文链接:https://www.cnblogs.com/dchipnau/p/5479126.html