Live555研究之二Sleep实现

时间:2024-10-30 08:37:02

Live555通过一个while循环来不断读取socket,判断是否有连接进来,但是Live555并没有使用Sleep函数来让线程休眠多少毫秒来降低CPU占用率。Live555是通过select函数来实现Sleep,先计算出距离下次事件的时间,然后让select超时为该时间值(tv_timeToDelay),如果有连接进来则处理,没有则等待直到超时。
int selectResult = select(fMaxNumSockets, &readSet, &writeSet, &exceptionSet, &tv_timeToDelay);

static BasicTaskScheduler* createNew(unsigned maxSchedulerGranularity = 10000/*microseconds*/);
创建BasicTaskScheduler对象的时候会将10毫秒作为默认的事件时间间隔,创建定时任务。
DelayQueue是一个循环队列,在BasicTaskScheduler::SingleStep() 结束前会调用该队列的handleAlarm()函数,在handleAlarm()内会首先释放当前Event,然后调用Event的handleTimeout()函数,由于在DelayQueue的派生类AlarmHandler中已经把handleTimeout()函数改写了,每次调用之前会先通过函数指针调用函数来创建一个新的AlarmHandle。然后再调用DelayQueueEntry::handleTimeout()。这样保证每处理完一个Event,又会创建一个新的Event,确保工程能执行下去,而且队列里的节点又不会无限制增长。

virtual void handleTimeout() {
  (*fProc)(fClientData);
  DelayQueueEntry::handleTimeout();
}

对于循环队列DelayQueueEntry,如果要插入新的Event,将会匹配时间修改当前Event,再把新Event插入的到当前Event的前面,再修改前后指针,形成新的循环队列。
void DelayQueue::addEntry(DelayQueueEntry* newEntry) {
  synchronize();

  DelayQueueEntry* cur = head();
  while (newEntry->fDeltaTimeRemaining >= cur->fDeltaTimeRemaining) {
    newEntry->fDeltaTimeRemaining -= cur->fDeltaTimeRemaining;
    cur = cur->fNext;
  }

  cur->fDeltaTimeRemaining -= newEntry->fDeltaTimeRemaining;

  // Add "newEntry" to the queue, just before "cur":
  newEntry->fNext = cur;
  newEntry->fPrev = cur->fPrev;
  cur->fPrev = newEntry->fPrev->fNext = newEntry;
}

计算延迟时间是在函数DelayQueue::synchronize()中进行的,保存当前时间,然后和上一次同步的时间做比较,判断还有多少富余时间,再将富余时间返回。

以前开发流媒体服务器,在进行帧率处理时使用Sleep让线程等待,但是Sleep误差在40毫秒左右,导致声音不流畅,后来还是改用其他函数进行优化。socket中的select()函数的误差应该会小些。