《54时间片轮询多任务操作系统》由会员分享,可在线阅读,更多相关《54时间片轮询多任务操作系统(31页珍藏版)》请在金锄头文库上搜索。
1、5.4 时间片轮询多任务操作系统 目 录1概述 2整体规划 3任务控制块 4内部变量初始化 5创建任务6启动多任务环境 longjmpInIsr() 9任务调度 7时钟节拍中断 8任务延时 10删除任务 11运行的任务难以得知其他任务状态,任务切换时机难以把握。如果一个任务死掉,势必造成整个系统死掉。协作式多任务系统 任务 协作式多任务系统的特点 安全性 复杂性 协作式多任务系统中,任务切换需正在运行的任务主动让出CPU,这不仅带来一些安全隐患,而且使程序设计相当的复杂。任务调度任务调度交给操作系统,引入调度算法 调度算法 时间片轮询 1优先级调度2带优先级调度的时间片轮询 3调度算法 时间片
2、轮询 1t t 任务的运行时间 时间片轮询系统中任务运行情况 在时间片轮询操作系统中,CPU的执行时间被划分为若干时间片,然后让处于就绪状态的任务,按顺序轮流占用CPU。当时间片用完时,即使任务未执行完,系统也剥夺此任务的CPU使用权力。时间片长度t一般为110ms 优先级调度2带优先级调度的时间片轮询 3任务A 任务B任务C 所有任务相同对待,分时运行。调度算法 时间片轮询 1优先级调度2带优先级调度的时间片轮询 3+ 低优先级 + 中优先级 + 高优先级 任务A 任务B任务C t 高优先级任务先运行 t 高优先级任务抢占低优先级任务 不同任务不同对待,优先级高任务的先运行。调度算法 时间片
3、轮询 1优先级调度2带优先级调度的时间片轮询 3 这种调度算法情况较复杂,类型较多,自己去学习了解。任务切换时机 分配给任务的时间片已到 任务主动请求调度 12 任务在调用操作系统提供的“管理”类服务(如删除任务等)和“等待”类服务(如延时、获取信号量、等待消息等)时,会主动请求调度。 操作系统采用一个周期性的中断来管理时间片,在这个中断服务函数中,判断运行的任务是否用完了时间片。中断中中断中切换任务切换任务 使用时间片轮询调度的操作系统中,会在两种下进行任务切换。 目 录2整体规划 1概述 34任务控制块 内部变量初始化 时间片轮询操作系统规划 时间片轮询调度算法时间片轮询多任务操作系统协作
4、式多任务系统 TinyOS51 V1.0 TinyOS51 V1.1 TinyOS51 V1.1采用最简单的时间片轮询调度算法,在每个时钟节拍中断时调度,即分配给任务的时间片为一个时钟节拍。 这样,在任务控制块中不仅不需要保存时钟任务剩余的时钟节拍,而且也不必编写计算任务的剩余时间和设置任务时间片的代码。TinyOS51从V1.0到V1.1的改变 TinyOS51 V1.0TinyOS51 v1.1任务调度函数tnOsSched()_tnOsSched()任务延时函数无tnOsTimeDly()时钟节拍处理函数无tnOsTimeTick()TinyOS51 V1.0和TinyOS51 V1.1
5、的API不同点 提供操作系统的一种基本服务延时服务,延时以时钟节拍为单位。 在TinyOS51中,时钟节拍中断由用户实现,在时钟节拍中断处理函数中调用tnOsTimeTick()。void task0(void) TMOD = (TMOD & 0 xF0) | 0 x01; TL0 = 0 x00; / TH0 = 0 x00; / 初始化timer0,即 TR0 = 1; / 初始化时钟节拍 ET0 = 1; / 中断。 TF0 = 0; / while (1) _GucTask0+; /* * 一个简单的任务,无限循环中让 * _GucTask0+。 */void task1(void)
6、while (1) _GucTask0+; /* * 用户实现时钟节拍中断服务函数, * 并调用tnOsTimeTick()。 */void timer0ISR(void) _interrupt1 tnOsTimeTick();/* * 1. 初始化系统 * 2. 创建任务 * 3. 启动系统 */void main(void) tnOsInit(); tnOsTaskCreate(task0, _GucTaskStks0; tnOsTaskCreate(task1, _GucTaskStk1); tnOsStart();资源配置与示例 n任务函数 task0()和task1() n时钟节拍中
7、断服务函数timer0ISR() nmain函数 main() static idata unsigned char _GucTaskStk232;static unsigned char _GucTask0;static unsigned char _GucTask1;/ 分配任务堆栈/ 任务0测试变量 / 任务1测试变量 全局变量定义 函数实现 目 录3任务控制块 45内部变量初始化 创建任务 12概述 整体规划任务控制块 TinyOS51 V1.1增加了延时服务功能,因此,在TCB中增加了一个记录时间的成员uiTicks。#define _TN_TASK_FLG_DEL 0 x00 /
8、任务被删除#define _TN_TASK_FLG_RDY 0 x01 / 任务就绪#define _TN_TASK_FLG_DLY 0 x02 / 任务延时struct tn_os_tcb jmp_buf jbTaskContext; / 任务上下文 unsigned char ucTaskStat; / 任务状态 unsigned int uiTicks; / 任务延时时间 ;typedef struct tn_os_tcb TN_OS_TCB;static data TN_OS_TCB _GtcbTasksTN_OS_MAX_TASKS; / 任务控制块数组与任务控制块相关代码: 目 录
9、4内部变量初始化 56创建任务 启动多任务环境 23整体规划 任务控制块 tnOsInit() void tnOsInit (void) TN_OS_TASK_HANDLE thTask; / 操作的任务 for (thTask = 0; thTask TN_OS_MAX_TASKS; thTask+) _GtcbTasksthTask.ucTaskStat = _TN_TASK_FLG_DEL; / 任务初始处于删除状态 _GtcbTasksthTask.uiTicks = 0; / 设置初值 _GthTaskCur = 0; / 初始运行0号任务 由于TCB增加了一个uiTicks,则在t
10、nOsInit()中进行初始化。 OS初始化函数代码: 目 录5创建任务67启动多任务环境 任务调度 34任务控制块内部变量初始化 通常,为了提高可移植性,采用一个宏或函数来编写实现开中断和关中断程序。由于TinyOS51仅适合80C51系列单片机,故直接使用“EA=0”和“EA=1”。创建任务函数tnOsTaskCreate() 由于tnOsTaskCreate()要操作TCB,而时钟节拍中断中也要操作TCB,因此tnOsTaskCreate()中操作TCB的代码为临界区代码,要避免被时钟节拍中断打断。 TinyOS51中采用开/关中断的方式解决此问题。TN_OS_TASK_HANDLE t
11、nOsTaskCreate(void (*pfuncTask)(void), idata unsgined char *pucStk)TN_OS_TASK_HANDLE thRt;for (thRt = 0; thRt TN_OS_MAX_TASKS; thRt+) EA = 0; / 禁止中断if (_GtcbTasksthRt.ucTaskStat = _TN_TASK_FLG_DEL) setTaskJmp(pfuncTask, pucStk, _GtcbTasksthRt.jbTaskContext); _GtcbTaskthRt.ucTaskStat = _TN_TASK_FLG_R
12、DY; EA = 1; / 允许中断 return thRt;EA = 1; / 允许中断 目 录6启动多任务环境 78任务调度 时钟节拍中断 45内部变量初始化 创建任务 tnOsStart() 在TinyOS51 V1.1中,如果不允许中断,则时钟节拍中断服务程序不会运行,因此,在tnOsStart()中增加允许中断的代码。 void tnOsStart (void) EA = 1; / 允许中断longjmp (_GtcbTask0.jbTaskContext); / 执行0号任务 tnOsInit()中_GthTaskCur = 0,即当前运行任务为0号任务。 目 录7任务调度 89时
13、钟节拍中断 longjmpInIsr() 56创建任务 启动多任务环境 _tnOsSched() tnOsSched() 开/关中断代码_tnOsSched() TinyOS51 V1.0 TinyOS51 V1.1 任务调度函数_tnOsSched()中也要操作TCB,因此也需要加入开/关中断代码包含临界区。另外,_tnOsSched()不再提供给任务直接调用,仅供内部调用,因此添加前缀“_”。保护临界资源 目 录8时钟节拍中断 9longjmpInIsr() 任务延时 67启动多任务环境 任务调度 10 如果uiTicks不为0,则uiTicks-,即缩短延时时间。未使用任务状态标志判断任
14、务是否处于延时状态。这是因为TinyOS51更高的版本具有超时功能,需要使用uiTicks来判断任务是否超时。 如果uiTicks为0,则将任务设置为就绪状态。为了向上兼容超时代码,即区分系统服务是正常返回还是超时返回,未直接将任务设置为就绪状态,而使用“|=”操作。时钟节拍中断 大多数操作系统中的延时管理和中断服务程序中的任务切换功能,分别是用两个函数实现的,由于TinyOS51 V1.1是纯粹的时间片轮询操作系统,非时钟节拍中断的中断服务程序不进行任务切换操作,因此将二者合二为一。 for (thTask = 0; thTask TN_OS_MAX_TASKS;thTask+) if (_
15、GtcbTasksthTask.uiTicks != 0) _GtcbTasksthTask.uiTicks-; / 缩短延时时间 if (_GtcbTasksthTask.uiTicks = 0) _GtcbTasksthTask.ucTaskStat |= _TN_TASK_FLG_RDY; / 设置任务就绪状态位 延时管理 1任务切换 2 对于80C51来说,规定:一般函数返回使用RET指令,而中断返回使用RETI指令。由于longjmp()函数是使用RET指令返回的,如果在时钟节拍中断中继线使用longjmp(),则任务切换后CPU会认为中断仍未退出,同级中断(包括自身)将被屏蔽,从而
16、造成整个系统执行错误。因此必须将longjmp()函数改为longjmpInIsr()。时钟节拍中断 大多数操作系统中的延时管理和中断服务程序中的任务切换功能,分别是用两个函数实现的,由于TinyOS51 V1.1是纯粹的时间片轮询操作系统,非时钟节拍中断的中断服务程序不进行任务切换操作,因此将二者合二为一。 for (thTask = 0; thTask = TN_OS_MAX_TASKS) thTmp2 = 0; if (_GtcbTasksthTmp2.ucTaskStat & _TN_TASK_FLG_RDY) != 0) cTmp1 = setjump(_GtcbTask_GthTaskCur.jbTaskContext); / 保持上下文 if (cTmep1 = 0) _GthTaskCur = thTmp2; longjmpInIsr(_GtcbTasksthTmp2.jbTaskContext); / 中断中切换上下文 延时管理 1任务切换 2 目 录9longjmpInIsr() 任务延时 删除任务 78任务调度 时钟节拍中断 1110中断中切换任务 在中断中切换任