μcOS-II多任务实验报告(RMS、EDF调度)

一、实验概述

  • 实验目的:在ucOS-II上多任务实验,要求考虑到任务间存在共享资源的情况。
  • 本次实验使用到的调度策略为RMS和EDF。
  • 其中RMS为固定优先级的调度,其实就是从就绪态中找到优先级最大的,就是周期最小的让它进入运行态。
  • 而EDF调度起源于EDD算法,EDD算法要求最小化最大延迟,只要将ddl近的设为高优先级就行了,而EDF要求进一步支持任务在任意时间到达,即EDF需要动态的维持任务的优先级。
  • 共享资源利用信号量OSSemCreate(1)实现
  • 备注:在提交的作业中,我把Sched_EDF()注释掉了,默认输出结果是RMS调度(有共享资源)。想看EDF的结果就到oscore.c中,找到OS_SchedNew(),把RMS调度注释掉,清除EDF的注释。想看无共享资源就到main.c,找到对任务resource初始化的代码,注释掉即可。

二、环境搭建

本实验使用的μcOS-II系统,是移植到VS2017上的。在打开解决方案OS2.sln后,发现其使用的Windows SDK版本较旧,因此需要在项目属性中重新指定SDK版本。重新配置后,项目能够正常编译运行。

三、代码分析

在借助资料,研读代码执行流程后,我认识到:

  • 任务在main.c中创建,新建任务后会生成对应的TCB程序控制块(定义在ucos-ii.h中的OS_TCB),并链接到TCB链表中头,链表尾是程序创建的空闲任务。
  • 任务在while中无限循环,cpu利用TimeTick(在os_cpu_c.c中)在这些任务中切换。每隔一段时间中断,中断调用函数OSTickW32,顺序执行OSIntEnter()、OSTimeTick()、OSIntExit()、OSIntCurTaskResume()。
  • 中断主要使用的函数OSTimeTick()在os_core.c中,它会遍历OSTCBList,将所有TCB的等待时间(ptcb->OSTCBDly)减一,如果那个TCB的等待时间变成0了,就把它的优先级添加到任务就绪表。
  • 再看OSIntExit(),也在os_core.c中,通过OSPrioHighRdy,然后去OSTCBPrioTbl数组找到了对应的TCB,赋值给OSTCBHighRdy指针。然后调用了上下文切换函数OSIntCtxSw()函数(用来切换线程,修改了OSTCBCur,OSPrioCur)。
  • 值得注意的是,在OSIntExit()中程序是通过OS_SchedNew()来取得当前就绪态中优先级最高的TCB块的,用OSPrioHighRdy表示。
  • 而OS_SchedNew()(同在os_core.c中),仅仅通过三行关键代码(就在<=63的那个if里)就完成了对RMS的支持。如果想修改调度算法,应该就是改这里了。

四、实验步骤

1 给TCB块添加扩展

如下图所示,定义在ucos_ii.h中的OS_TCB下面,在创建任务时作为TCB扩展传入。OS_TCB的OSTCBExtPtr指针指向的就是这个tcb_ext_info。目的是为执行任务时提供必要的信息

2 创建并执行任务

  • 如下图所示,进行了任务创建(createTasks)与任务执行(startTasks)。都在main.c中。

  • 任务创建要初始化resource,即信号量的事件控制块指针,然后使用OSTaskCreateExt()方法创建任务。其中任务的id号=任务的优先值=任务的周期数。因为任务的优先级和任务的优先值成反比。其中对于RMS调度,任务的优先级与任务的周期成反比,也就是说任务优先值是可以直接用周期表示的。其中对于EDF调度,这个动态优先级调度,也省得我重新为三个任务指定初始优先值,对于这个用例我就默认任务初始优先值等于周期长度。

  • 任务执行先使用while循环来做一个周期的任务,利用时钟中断来切换任务。所以这个周期可能会顺利执行完,也有可能被抢占,执行可能会请求信号量。一个周期做完了,要重置rest_c并记得归还信号量。







3 添加时钟中断对剩余执行时间和剩余周期的操作

在os_core.c中每次timetick,把执行任务的rest_c减去1,并遍历TCB,把所有任务的rest_p减去1,并看哪个任务已经OSTCBDly已经为0,即进入就绪态时再重置任务的rest_p。

4 实现调度

注释掉OS_SchedNew()中的函数,在结尾插入我的新函数Sched_RMS和Sched_EDF()。

4.1 RMS调度

考虑到要实现共享资源,这三行代码还不太利于我操作,尤其是目前我对代码了解还不深的情况下。考虑到RMS较为简单,我就用自己添加的数据结构重新写了RMS调度。重新写好处是,一来EDF完全可以复用它,只要把就绪态中周期最小的改为就绪态中剩余周期最小的就行了;二来,这样方便我过滤掉就绪态中资源被别的任务占用的任务。

主要思路是初始优先级选63,遍历TCB链表(不包括61,62),找到就绪态中可请求资源或无需资源的任务中优先级最高(周期最短)的任务,如果需要请求资源,就给它资源。



4.2 EDF调度

EDF复用RMS的代码,只要把就绪态中周期最小的改为就绪态中剩余周期最小的就行了。



5 输出

两种输出,任务完成与任务抢占

  • 任务完成会调用OSTimeDly(),完成的printf写在该函数里
  • 任务抢占会走OSIntExit(),在该函数里判断一下是不是抢占,如果是就printf抢占的内容。

6 结果展示

6.1 RMS 无共享资源

6.2 EDF 无共享资源

6.3 RMS 有共享资源(最高优先级和最低优先级共享)

6.4 EDF有共享资源(最高优先级和最低优先级共享)

五 值得注意的部分

  • 遍历的时候要注意不单单有优先级为63的空闲任务,我还发现了有优先级为62、61的任务,为了方便输出的观察,我是直接将其过滤掉,不让其影响我的输出。
  • 注意可能存在这种情况,在B任务执行结束时,即rest_c=0时,如果A任务优先级高于B,会发生A先抢占B,然后A执行完之后……然后B任务才能complete。这点给我造成了很大的两点麻烦。
    • 一个是我不希望造成A抢占B,然后某任务再还给B的这种输出,而是应该让B直接完成,然后再让A做其他操作。这个我是通过给任务抢占的判断添加限制条件(在任务抢占输出那一部分),让B能跳过被抢占,直接完成,完成后再转给A。
    • 另一个是我不希望由于A抢占B,B不能立即complete造成资源还在B手里,不能归还,影响其它任务的执行。这点我通过在调度函数最后请求资源时做条件判断,避免了这种情况。
  • 给代码加入信号量部分后,发现代码运行出问题了,导致进入临界区函数OS_ENTER_CRITICAL()没法使用了,导致下面代码运行不了。在找到该函数源码后,依据网上给的思路,我试着换到另一个if判断,并注释掉了一部分代码后,能够正常运行。
  • 还有一个问题是,时钟频率太快导致代码来不及运行,这个我一开始不知道,毫无办法,后来把os_cfg.h文件中#define OS_TICKS_PER_SEC 从100改成10,这样运行就没问题了。

六 源码

github源码

基于μcOS-II实时操作系统源码实现RMS和EDF调度(共享资源)的更多相关文章

  1. 适合新手:从零开发一个IM服务端(基于Netty,有完整源码)

    本文由“yuanrw”分享,博客:juejin.im/user/5cefab8451882510eb758606,收录时内容有改动和修订. 0.引言 站长提示:本文适合IM新手阅读,但最好有一定的网络 ...

  2. 基于vitamio的网络电视直播源码

    这个项目是基于vitamio的网络电视直播源码,也是一个使用了vitamio的基于安卓的网络直播项目源码,可能现在网上已经有很多类似这样的视频播放应用了,不过这个还是相对来说比较完整的,希望这个案例能 ...

  3. 第6章 RTX 操作系统源码方式移植

    以下内容转载自安富莱电子: http://forum.armfly.com/forum.php 本章教程为大家将介绍 RTX 操作系统源码方式移植,移植工作比较简单,只需要用户添加需要的源码文件即可, ...

  4. 基于jQuery经典扫雷游戏源码

    分享一款基于jQuery经典扫雷游戏源码.这是一款网页版扫雷小游戏特效代码下载.效果图如下: 在线预览   源码下载 实现的代码. html代码: <center> <h1>j ...

  5. Spring3.2 中 Bean 定义之基于 XML 配置方式的源码解析

    Spring3.2 中 Bean 定义之基于 XML 配置方式的源码解析 本文简要介绍了基于 Spring 的 web project 的启动流程,详细分析了 Spring 框架将开发人员基于 XML ...

  6. Spark源码分析之六:Task调度(二)

    话说在<Spark源码分析之五:Task调度(一)>一文中,我们对Task调度分析到了DriverEndpoint的makeOffers()方法.这个方法针对接收到的ReviveOffer ...

  7. 基于Linux平台的libpcap源码分析和优化

    目录 1..... libpcap简介... 1 2..... libpcap捕包过程... 2 2.1        数据包基本捕包流程... 2 2.2        libpcap捕包过程... ...

  8. 基于ReentrantLock的AQS的源码分析(独占、非中断、不超时部分)

    刚刚看完了并发实践这本书,算是理论具备了,看到了AQS的介绍,再看看源码,发现要想把并发理解透还是很难得,花了几个小时细分析了一下把可能出现的场景尽可能的往代码中去套,还是有些收获,但是真的很费脑,还 ...

  9. Android版数据结构与算法(二):基于数组的实现ArrayList源码彻底分析

    版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 本片我们分析基础数组的实现--ArrayList,不会分析整个集合的继承体系,这不是本系列文章重点. 源码分析都是基于"安卓版" ...

随机推荐

  1. Codeforces Round #648 (Div. 2) F. Swaps Again

    题目链接:F.Swaps Again 题意: 有两个长度为n的数组a和数组b,可以选择k(1<=k<=n/2)交换某一个数组的前缀k和后缀k,可以交换任意次数,看最后是否能使两个数组相等 ...

  2. poj1180 Batch Scheduling

    Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 3590   Accepted: 1654 Description There ...

  3. 牛客练习赛70 B.拼凑 (序列自动机)

    题意:有一个模板串,有\(T\)个字符串,从字符串中找到某个子串,使得这个子串中的子序列包含模板串,求最短的子串的长度. 题解:找子序列,很容易想到序列自动机,根据序列自动机的原理,我们一定可以确保除 ...

  4. Codeforces Beta Round #92 (Div. 2 Only) B. Permutations

    You are given n k-digit integers. You have to rearrange the digits in the integers so that the diffe ...

  5. read()、readline()、readlines() -- Python

    文本文件:readfile.txt 详细描述: read()                  #一次性读取文本中全部的内容,以字符串的形式返回结果 readline()           #只读取 ...

  6. kubernetes跑jenkins动态slave

    使用jenkins动态slave的优势: 服务高可用,当 Jenkins Master 出现故障时,Kubernetes 会自动创建一个新的 Jenkins Master 容器,并且将 Volume ...

  7. 7A - Kalevitch and Chess

    A. Kalevitch and Chess time limit per test 2 seconds memory limit per test 64 megabytes input standa ...

  8. 信号量解决理发师问题(barber)

    问题描述及思路         代码 一些细节见注释 这里ret应该用int..忘了改了.         运行结果 因为座位数和到来最大间隔的原因,没有出现全部椅子被占用的情况  

  9. gradle中的增量构建

    目录 简介 增量构建 自定义inputs和outputs 运行时API 隐式依赖 输入校验 自定义缓存方法 输入归一化 其他使用技巧 gradle中的增量构建 简介 在我们使用的各种工具中,为了提升工 ...

  10. shit vuepress docs

    shit vuepress docs https://deploy-preview-2764--vuepress.netlify.app/guide/directory-structure.html ...