19 BasicTaskScheduler0 基本任务调度类基类(一)——Live555源码阅读(一)任务调度相关类
这是Live555源码阅读的第二部分,包括了任务调度相关的三个类。任务调度是Live555源码中很重要的部分。
本文由乌合之众 lym瞎编,欢迎转载 http://www.cnblogs.com/oloroso/
本文由乌合之众 lym瞎编,欢迎转载 my.oschina.net/oloroso
BasicTaskScheduler0 基本任务调度类基类#
BasicTaskScheduler0
是一个用作传递的类,它继承自TaskScheduler
,又派生出BasicTaskScheduler
。其定义在live555sourcecontrol\UsageEnvironment\include\BasicUsageEnvironment0.hh
文件中。
这个类实现了TaskScheduler中的纯虚接口
,并增加了一些数据成员。其中比较重要的两个是fDelayQueue
(延时队列)和fHandlers
(处理程序集合/链表)。
下面是其定义代码,里面有一些是对注释的翻译。#
class HandlerSet; // forward #define MAX_NUM_EVENT_TRIGGERS 32 // An abstract base class, useful for subclassing 抽象基类,用于子类化 // (e.g., to redefine the implementation of socket event handling) // 例如,重新定义socket事件处理的实现 class BasicTaskScheduler0 : public TaskScheduler { public: //析构的时候 delete fHandlers virtual ~BasicTaskScheduler0(); //设置select轮询的超时时间的最大值,如果maxDelatTime不大于0,那么就设置为一百万秒 virtual void SingleStep(unsigned maxDelayTime = 0) = 0; // "maxDelayTime" is in microseconds. It allows a subclass to impose a limit // maxDelayTime 单位是微秒,它允许一个子类施加限制 // on how long "select()" can delay, in case it wants to also do polling. // 多长时间”select()”可以延迟,如果它想做轮询。 // 0 (the default value) means: There's no maximum; just look at the delay queue // 0作为默认值,意思是:没有最大;只是看看延迟队列 public: // Redefined virtual functions:重新定义虚函数 /* 调度延时任务 * 1、创建一个AlarmHandler对象(定时处理);(new AlarmHandler(proc, clientData, timeToDelay);) * 2、将创建的alarmHandler对象添加到fDelayQueue中;(fDelayQueue.addEntry(alarmHandler)) * 3、返回这个alarmHandler的token标志 */ virtual TaskToken scheduleDelayedTask(int64_t microseconds, TaskFunc* proc, void* clientData); /* 取消调度延时任务 * 1、从fDelayeQueue中removeEntry这个prevTask * 2、设置prevTask=NULL * 3、delete这个prevTask标识的alarmHandler对象 */ virtual void unscheduleDelayedTask(TaskToken& prevTask); /* 做事件循环 * 1、判断watchVariable !=0 && *watchVariable != 0是否成立,若成立,函数返回 * 2、调用函数SingleStep();函数返回后继续做步骤1 */ virtual void doEventLoop(char* watchVariable); /* 创建事件触发器ID * 从fTriggeredEventHandlers数组中寻找一个没有使用的位置 pos。如果没有空位,函数返回0 * 将eventHandlerProc放置到上述数组 pos 位置 * 将fTriggeredEventClientDatas数组 pos 位置置为NULL * 设置fLastUsedTriggerMask的第 pos 位为1 * 设置fLastUsedTriggerNum为 pos * 返回fLastUsedTriggerMask的值 */ virtual EventTriggerId createEventTrigger(TaskFunc* eventHandlerProc); /* 删除事件触发器 eventTriggerId可能代表多个事件触发器 * 设置 fTriggersAwaitingHandling &=~ eventTriggerId * 即将fTriggersAwaitingHandling中对应于eventTriggerId的非零位 置零 * 从fTriggeredEventHandlers和fTriggeredEventClientDatas中将对应的位置置为NULL */ virtual void deleteEventTrigger(EventTriggerId eventTriggerId); /* 触发事件 * 从fTriggeredEventClientDatas找到eventTriggerId对应的位置,设置为clientData * 将fTriggersAwaitingHandling中对应eventTriggerId中的非0位置为1 */ virtual void triggerEvent(EventTriggerId eventTriggerId, void* clientData = NULL); protected: BasicTaskScheduler0(); protected: // implement vt.实施,执行; 使生效,实现; 落实(政策); 把…填满;n.工具,器械; 家具; 手段;[法]履行(契约等); // To implement delayed operations: 实施延迟操作: DelayQueue fDelayQueue; // To implement background reads: 实施后台读 HandlerSet* fHandlers; //处理程序描述对象链表指针 int fLastHandledSocketNum; //当前最近一个调度的HandlerDescriptor对象的socketNum标识 // To implement event triggers: 实施时间触发器 // fTriggersAwaitingHandling触发等待处理的 fLastUsedTriggerMask 最后使用触发器的位置置1 // implemented as 32-bit bitmaps 实现是32位的比特位图 EventTriggerId fTriggersAwaitingHandling, fLastUsedTriggerMask; TaskFunc* fTriggeredEventHandlers[MAX_NUM_EVENT_TRIGGERS]; //保存事件触发器 void* fTriggeredEventClientDatas[MAX_NUM_EVENT_TRIGGERS]; //保存触发事件客户端数据 unsigned fLastUsedTriggerNum; // in the range(范围) [0,MAX_NUM_EVENT_TRIGGERS) 最后使用触发器的 };
BasicTaskScheduler0的构造与析构#
BasicTaskScheduler0
的构造内容不多,但是从这里开始要介绍的东西很多。还有注意,这个构造函数是protected
权限的。
先来分析一下它的各个数据成员。
int fLastHandledSocketNum;
从字面意思来看,这个成员的意思是保存最后一个处理socket的。但是这只是猜测。这里我们回到前面去看HandlerDescriptor类的定义。其类定义中有一个成员socketNum,用来表示HandlerDescriptor在链表中的唯一存在
。是不是这两者就有关联了呢?没错,确实是这样的。这个变量代表的是最后一个被加入的HandlerDescriptor对象
。
fTriggersAwaitingHandling
和fLastUsedTriggerMask
这两个一起来说。
这两者的类型是EventTriggerId
,实质上是无符号32未整型(u_int32_t)
。这两个变量和后面的两个数组对应起来看,这两个数组都是MAX_NUM_EVENT_TRIGGERS
个元素的,也就是32。而这里两个变量是32bit,它们的每一个位与数组的一个元素对应是否就刚刚好呢?这里先不说,后面会解释的。(fTriggersAwaitingHandling等待触发集,fLastUsedTriggerMask最近使用的触发器)
fLastUsedTriggerNum
这个参数表示的是最后一个使用触发器的位置(在fTriggeredEventHandlers数组中的下标)。它的范围是[0,31]。将其初始化为31,是因为每一次创建触发器的时候会使用这个值。见createEventTriggerd方法。
数组fTriggeredEventHandlers
用于保存事件处理程序函数地址
,它的每一个元素是一个函数指针。
数组fTriggeredEventClientDatas
用于保存事件处理程序函数调用时候的参数
,它的元素是void*
类型。
DelayQueue fDelayQueue;
是一个延时队列,前面介绍过。用于延时处理事件。注意这里这个链表的节点将是AlarmHandler
对象。
HandlerSet* fHandlers;
这一个用于保存事件处理程序和其客户数据。要注意的是这里是一个指针,而不是对象。在构造的时候创建了一个对象。
BasicTaskScheduler0::BasicTaskScheduler0() : fLastHandledSocketNum(-1), fTriggersAwaitingHandling(0), fLastUsedTriggerMask(1), fLastUsedTriggerNum(MAX_NUM_EVENT_TRIGGERS-1) { fHandlers = new HandlerSet; //创建对象 for (unsigned i = 0; i < MAX_NUM_EVENT_TRIGGERS; ++i) { fTriggeredEventHandlers[i] = NULL; fTriggeredEventClientDatas[i] = NULL; } }
BasicTaskScheduler0的析构就简单很多了。前面说了,只要一个成员fHandlers是指针的,并且在构造的时候动态创建了一个对象给它。所以析构的时候就只是将其delete了。
BasicTaskScheduler0::~BasicTaskScheduler0() { delete fHandlers; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理