关键词:
计划任务(TaskScheduler)探讨
socket handler 为
typedef void BackgroundHandlerProc (void* clientData, int mask);
event handler为
typedef void TaskFunc(void* clientData);
delay task 为
typedef void TaskFunc(void* clientData);// 跟event handler一样。
再看一下向任务调度对象添加三种任务的函数的样子:
socket handler 为:
void setBackgroundHandling(int socketNum, int conditionSet ,BackgroundHandlerProc*
handlerProc, void* clientData)
EventTriggerId createEventTrigger(TaskFunc* eventHandlerProc)
delay task 为:
TaskToken scheduleDelayedTask(int64_t microseconds, TaskFunc* proc,void*
clientData)
(socketNum 即是socket() 返回的那个socket 对象)。conditionSet 也是需要的,它用于
表明socket 在select 时查看哪种装态,是可读?可写?还是出错?proc 和clientData 这两
个参数就不必说了(真有不明白的吗?)。再看BackgroundHandlerProc 的参数,socketNum
不必解释,mask是什么呢?它正是对应着 conditionSet ,但它表明的是 select 之后的结果,
比如一个socket 可能需要检查其读/ 写状态,而当前只能读,不能写,那么mask中就只有
表明读的位被设置。
-
void BasicTaskScheduler
-
::setBackgroundHandling(int socketNum, int conditionSet, BackgroundHandlerProc* handlerProc, void* clientData)
-
if (socketNum < 0) return;
-
FD_CLR((unsigned)socketNum, &fReadSet);
-
FD_CLR((unsigned)socketNum, &fWriteSet);
-
FD_CLR((unsigned)socketNum, &fExceptionSet);
-
if (conditionSet == 0)
-
fHandlers->clearHandler(socketNum);
-
if (socketNum+1 == fMaxNumSockets)
-
--fMaxNumSockets;
-
-
else
-
fHandlers->assignHandler(socketNum, conditionSet, handlerProc, clientData);
-
if (socketNum+1 > fMaxNumSockets)
-
fMaxNumSockets = socketNum+1;
-
-
if (conditionSet&SOCKET_READABLE) FD_SET((unsigned)socketNum, &fReadSet);
-
if (conditionSet&SOCKET_WRITABLE) FD_SET((unsigned)socketNum, &fWriteSet);
-
if (conditionSet&SOCKET_EXCEPTION) FD_SET((unsigned)socketNum, &fExceptionSet);
-
-
的项,EventTriggerId 是一个32位整数,因为数组是32项,所以用EventTriggerId 中的
第n 位置1表明对应数组中的第n 项。成员变量fTriggersAwaitingHandling 也是
EventTriggerId 类型,它里面置 1 的那些位对应了数组中所有需要处理的项。这样做节省了
内存和计算,但降低了可读性,呵呵,而且也不够灵活,只能支持32项或64项,其它数
量不被支持。以下是函数体
-
EventTriggerId BasicTaskScheduler0::createEventTrigger(TaskFunc* eventHandlerProc)
-
unsigned i = fLastUsedTriggerNum;
-
EventTriggerId mask = fLastUsedTriggerMask;
-
-
do
-
i = (i+1)%MAX_NUM_EVENT_TRIGGERS;
-
mask >>= 1;
-
if (mask == 0) mask = 0x80000000;
-
-
if (fTriggeredEventHandlers[i] == NULL)
-
// This trigger number is free; use it:
-
fTriggeredEventHandlers[i] = eventHandlerProc;
-
fTriggeredEventClientDatas[i] = NULL; // sanity
-
-
fLastUsedTriggerMask = mask;
-
fLastUsedTriggerNum = i;
-
-
return mask;
-
-
while (i != fLastUsedTriggerNum);
-
-
// All available event triggers are allocated; return 0 instead:
-
return 0;
-
触发事件时传入,见以下函数:
-
void BasicTaskScheduler0::triggerEvent(EventTriggerId eventTriggerId, void* clientData)
-
// First, record the "clientData". (Note that we allow "eventTriggerId" to be a combination of bits for multiple events.)
-
EventTriggerId mask = 0x80000000;
-
for (unsigned i = 0; i < MAX_NUM_EVENT_TRIGGERS; ++i)
-
if ((eventTriggerId&mask) != 0)
-
fTriggeredEventClientDatas[i] = clientData;
-
-
mask >>= 1;
-
-
-
// Then, note this event as being ready to be handled.
-
// (Note that because this function (unlike others in the library) can be called from an external thread, we do this last, to
-
// reduce the risk of a race condition.)
-
fTriggersAwaitingHandling |= eventTriggerId;
-
SingleStep()是不是更明了了?
delay task 添加时,需要传入 task 延迟等待的微秒(百万分之一秒)数( 第一个参数),这个
弱智也可以理解吧?嘿嘿。分析一下介个函数:
-
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());
-
DelayQueue 中实现。看一下handleAlarm():
-
void DelayQueue::handleAlarm()
-
//如果第一个任务的执行时间未到,则同步一下(重新计算各任务的等待时间)。
-
if (head()->fDeltaTimeRemaining != DELAY_ZERO) synchronize();
-
//如果第一个任务的执行时间到了,则执行第一个,并把它从队列中删掉。
-
if (head()->fDeltaTimeRemaining == DELAY_ZERO)
-
// This event is due to be handled:
-
DelayQueueEntry* toRemove = head();
-
removeEntry(toRemove); // do this first, in case handler accesses queue
-
//执行任务,执行完后会把这一项销毁。
-
toRemove->handleTimeout();
-
-
直接执行第一个完事。那就说明第一个就是最应该执行的一个吧?也就是等待时间最短的一
个吧?那么应该在添加任务时,将新任务跟据其等待时间插入到适当的位置而不是追加到尾
巴上吧?猜得对不对还得看fDelayQueue.addEntry(alarmHandler) 这个函数是怎么执行的。
-
void DelayQueue::addEntry(DelayQueueEntry* newEntry)
-
// 重新计算各项的等待时间
-
synchronize();
-
// 取得第一项
-
DelayQueueEntry* cur = head();
-
// 从头至尾循环中将新项与各项的等待时间进行比较
-
while (newEntry->fDeltaTimeRemaining >= cur->fDeltaTimeRemaining)
-
// 如果新项等待时间长于当前项的等待时间,则减掉当前项的等待时间。
-
newEntry->fDeltaTimeRemaining -= cur->fDeltaTimeRemaining;
-
cur = cur->fNext;
-
-
//循环完毕,cur 就是找到的应插它前面的项,那就插它前面吧
-
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;
-
有个问题,while循环中为什么没有判断是否到达最后一下的代码呢?难道肯定能找到大于
新项的等待时间的项吗?是的!第一个加入项的等待时间是无穷大的,而且这一项永远存在
于队列中。
鸟哥的linux私房菜之学习shellscript
运行程序的时候一般都是创建一个子程序来执行,所以子程序中的变量什么的在当前的shell下没法使用,但是如果使用source来执行就可以在当前shell下执行程序 查看详情
《鸟哥的linux私房菜--基础篇》学习
第四章显示日期与时间的指令:date输入:(base)liyihuadeMacBook-Pro:~liyihua$date输出:ThuJun608:44:02CST2019 显示日历指令:cal输入:(base)liyihuadeMacBook-Pro:~liyihua$cal输出:June2019SuMoTuWeThFrSa1234567891011121314151617 查看详情
鸟哥的linux私房菜——第十六章:学习shellscripts
视频链接: 1.什么是ShellScript (shell写的脚本)1.1干嘛学习shellscripts? ()1.2第一支script的撰写与执行1.3撰写shellscript的良好习惯建立 2.简单的shellscript练习: (read-p ... 查看详情
鸟哥的私房菜第0章
(1)计算机硬件的五大单元:输入单元、输出单元、CPU内部的控制单元、算术逻辑单元和内存五大部分。(2)CPU的种类:CPU的种类有两种,根据指令的执行时间和操作的复杂度分为精简指令集合复杂指令集。(3)一般的,文件... 查看详情
求鸟哥的linux私房菜全部视频教程百度网盘资源
参考技术A有老男孩的Linux视频教程+Mysql全套,你搜索下王飞资料下载,我博客上多了去了追问没有老段的教你学的吗?我想要百度云 查看详情
鸟哥的linux私房菜基础篇-第三版笔记
第三章主机规划于磁盘分区IDE硬盘机 /dev/hd[a-d]SCSI/SATA/USB /dev/sd[a-p]USB快闪碟 /dev/sd[a-p](与SATA相同)软盘驱动器 /dev/fd[0-1]打印机 25针:/dev/... 查看详情
求鸟哥的linux私房菜全部视频教程百度网盘资源
参考技术A鸟哥的没有有《linux就该这么学》的教程。首先鸟哥在开篇即提到了写书的缘由是因为记性不好,所以想写出一本能够放在案头的备忘录,对书籍的内容自然就没有了太多的筛选,反而一再的扩大知识范围,最终写出的... 查看详情
鸟哥的linux私房菜第四版有啥不同
第四版以最新更新的centos7为基础讲的,第三版的部分内容在新系统上不在适用。估计7以后是趋势,到现在仍然有大部分用7一下版本。推荐买第四版,7以前的版本也能有所了解。不过我觉得与其学Centos不如学redhat,《linux就该这... 查看详情
当时学习《鸟哥的linux私房菜-基础学习篇》记录的点
1.当执行一个指令的时候,举例来说【ls】,系统会依照PATH的设定去每个PATH定义的目录下搜寻文件名为ls的可执行文件,如果在PATH定义的目录中含有多个文件名为ls的可执行文件,那么先搜寻到的同名指令先被执行!2.使用echo$PAT... 查看详情
我看鸟哥的linux私房菜学,看老段教你学鸟哥的视频教程,用vmware装了个centos的虚拟机
我看鸟哥的Linux私房菜学,看老段教你学鸟哥的视频教程,用vmware装了个centos的虚拟机系统,可是每次运行都会特别卡,卡几十分钟,我的电脑去年买的索尼f15,主频1.6,硬盘1T,内存2G,我完全照着视频做的,可是为什么虚拟出... 查看详情
鸟哥私房菜笔记-1(s0_s3)
...下来先啃鸟哥这本吧,买的第三版,内容在鸟哥站上都有:鸟哥的 Linux 私房菜--基础学习篇目录 (繁体)http://cn.linux.vbird.org/linux_basic/linux_basic.php鸟哥的 Linux 私房菜--基础学习篇目录 (简体)http 查看详情
学鸟哥的linux私房菜需要多久才能学会?学会了能马上就业吗?
...般系统管理一个月,服务器架设也差不多一个月,结合鸟哥的相关视频,三个月应该能学会,后找一般的工作应该是没问题的。 参考技术B鸟哥的Linux私房菜内容是很丰富的,如果你有时间全部看懂并熟悉掌握的话,并结合一些... 查看详情
鸟哥的linux私房菜哪些内容要看
鸟哥的Linux私房菜,是最具知名度的Linux入门书《鸟哥的Linux私房菜基础学习篇》的最新版,全面而详细地介绍了Linux操作系统。由鸟哥著作,王世江改编。第一部分 Linux的规则与安装第0章 计算机概论第1章 Linux是什么第2章 ... 查看详情
阿里年薪破百架构师推荐:鸟哥的linux私房菜,搭配面试题,真香
在Linux实操的过程中,你是否有过这些疑问:如何提取日志中含有关键字的指定行,上一行或上几行?ln做了符号链接,对符号链接进行权限修改,原文件是否会受到影响?Shell脚本里有很多特殊符号,到底该怎么用?网上流传的... 查看详情
别人的linux私房菜(19)认识与分析日志文件
日志文件通常只有root可以读取,解决系统和网络方面的问题。/var/log/boot.log本次开机系统检测和启动硬件,和内核支持的相关功能的信息记录。/var/log/cron计划任务有没有被执行,是否正确编写等/var/log/dmesg开机时内核检测过程产... 查看详情
如何学习linux?买了鸟哥的linux私房菜和服务器架设,一边看书一边实践,已经看了三遍了
如何学习linux?买了鸟哥的linux私房菜和服务器架设,一边看书一边实践,已经看了三遍了,感觉这样学习前面看练习后面又忘了,效率不是太高,求linux高人指点如何学好linux,成为大师级别的?多看书,多实践。德国著名心理... 查看详情
博客总目录
1、linux相关1.1:鸟哥的私房菜基础篇1.2:内核与驱动学习1.3:杂七杂八1.4:有用的链接2、人工智能相关2.1:人工智能初识3、图像处理3.1:图像基础概念1.linux相关1.1鸟哥的私房菜基础篇:linux基础6-bashshell编程linux基础7-正则表达... 查看详情
计划任务
(整理自《鸟哥的Linux私房菜》基础篇)1.两种计划任务的方式• 一种是例行性的,就是每隔一定的周期要来办的事项;• 一种是突发性的,就是这次做完以后... 查看详情