SylixOS的RMS浅析

目 录

1. 知识简介    1

1.1 嵌入式实时操作系统    1

1.2 优先级调度算法    1

2. 技术实现    2

2.1 函数原型分析    2

2.2 使用流程    2

2.3 源码分析    3

2.4 示例演示    4

3. 参考资料    5

  1. 知识简介

  2. 嵌入式实时操作系统

    SylixOS操作系统是实时多任务嵌入式操作系统,所谓实时,是指系统的正确性不仅仅依赖于计算机的逻辑结果而且依赖于结果产生的时间。结果产生的时间就是通常所说的截止期限,描述系统实时性的指标主要有:

  3. 对紧急时间可预见性的快速响应;
  4. 高度的可调度性,所谓调度性是指系统在任务时间需求能够满足下的最高资源利用率,也就是平均每秒的及时执行的任务数量;
  5. 在暂时超负荷情况下的系统稳定性,即当系统超负荷运转导致不能满足所有任务的截止期限需求时,仍然能够保证关键任务的截止期限需求;

    对于实时而言,截止期限的要求是必须得到满足的,但是区分具体应用场合,这种时限要求的严格成都又有所不同。如果这种要求是绝对的,即不满足截止期限的要求计算结果就毫无意义甚至可能造成无法预料的结果或系统致命的错误,那就称之为硬实时系统(Hard Real Time System);SylixOS就是硬实时系统。在硬实时系统中如果出现了这样的情况就意味着巨大的损失和灾难,比如说日本福岛核电站中的堆芯温度控制系统如果没有对堆芯过热做出及时的冷却处理,后果不堪设想。当不满足截止期限的要求时计算机结果的可调度性逐渐减弱但是并不足以造成严重后果,系统仍然继续调度直至任务完成,则称为软实时系统(Soft Real Time System)。软实时系统是指如果在系统负荷较重的时候允许发生错过截止期限的情况而且不会造成太大的危害。硬实时系统和软实时系统的实现区别主要是,在选择调度算法上选择基于优先级调度的算法是以满足软实时系统的需求而且可以提供告诉的响应和大的系统吞吐率,而对硬实时系统来说需要使用的算法就应该是调度方式简单反应速度快的实时调度算法了。

  6. 优先级调度算法

    调度,是内核的主要职责之一,就是确定该轮到那个任务运行了。优先级抢占调度算法中,每个任务根据其重要程度的不同而被赋予一定的优先级。优先级抢占调度算法是指系统运行过程中高优先级的任务可以中断低优先级的任务,让处在就绪态的优先级最高的任务先运行。目前多数实时内核采用优先级可抢占的调度算法,主要原因有以下几点:

    首先,处理异常的任务可能需要抢占正在运行的任务,以便及时对异常做出响应;

    第二,任务的重要性不同,优先级可抢占使一些重要任务有可能抢占正在运行的任务;

    第三,允许任务抢占可得到更为有效的调度;

    根据不同的优先级分配方法,基于优先级的调度算法可以分为如下两种类型:

  7. 静态调度:

    静态调度是在系统开始运行前进行调度的,严格的静态调度在系统运行时无法对任务进行重新调度。静态调度的怒表是把任务分配到各个CPU,并对每一个CPU给出所要运行任务的静态运行顺序。静态调度算法实现简单,调度的额外开销小,在系统超载时可预测性好。但也具有很大的局限性,例如资源利用率低、受系统支持的优先级个数限制以及灵活性和自适应性差等。

    2.动态调度:

    在嵌入式实时系统中,动态调度依赖于任务的优先级。优先级可以静态分配或者依据不同的特征参数,如截止时间、空闲时间或关键性(即任务的重要程度)等进行动态分配。动态调度可以是抢占式的或非抢占式的。当检查到一事件时,动态抢占式算法立即决定是运行与此时间相关的任务,或继续执行当前的任务;对于动态非抢占式算法,它仅仅知道有另一个任务可以运行,在当前任务结束后,它才在就绪的任务中选择一个来运行。

    单调速率调度算法RMS(Rate Monotonic Scheduling)为每个周期线程指定一个固定不变的优先级,周期最短的线程优先级最高。周期越短,线程的到达频率越高,优先级也越高,这正是此策略被称为速率单调算法的原因。RMS算法也可用于多CPU环境,用于分配任务优先级。这种方法基于哪个任务执行的次数最频繁,执行最频繁的任务优先级最高。

    RMS的由来是从硬实时环境的初始定义开始的:

  8. 所有的任务都是周期性的,各个任务请求的截止期限呈周期性,同时具有恒定的时间间隔;
  9. 所有任务都必须在下一次任务请求到来之前完成;
  10. 所有的任务都是独立的,每一次任务请求不依赖于其他任务的执行或者初始化;
  11. 每个任务都存在一个恒定且非时变的执行时间,即CPU不间断地执行该任务的时间;
  12. 任何非周期的任务属于特殊任务,它们属于初始化或者是恢复错误的时间,仅当它们自身执行的时候才恩能够取代周期性任务,同时非周期性任务不存在有截止期限。
  13. 技术实现

  14. 函数原型分析


    #include <sched_rms.h>
    int sched_rms_init(sched_rms_t *prms, pthread_t thread);
    int sched_rms_destroy(sched_rms_t *prms);
    int sched_rms_period(sched_rms_t *prms, const struct timespec *period);

    函数 sched_rms_init 原型分析:
    l 此函数成功返回 0,失败返回-1 并设置错误号;
    l 参数 prms 是 RMS 调度器指针;
    l 参数 thread 是调用线程的句柄。
    函数 sched_rms_destroy 原型分析:
    l 此函数成功返回 0,失败返回-1 并设置错误号;
    l 参数 prms 是 RMS 调度器指针;

    函数 sched_rms_period 原型分析:
    l 此函数成功返回 0,失败返回-1 并设置错误号;
    l 参数 prms 是 RMS 调度器指针;
    l 参数 period 是程序执行周期。

  15. 使用流程

    SylixOS中RMS调度器使用流程如图 2-1所示。

    图 2-1RMS调度器使用流程图

  16. 源码分析

  17. 初始化调度器时,如图 2-2所示调用API_ThreadSetSchedParam()函数设置线程调度参数,首先将线程调度策略设置为FIFO(先入先出);然后将该线程设置为LW_OPTION_RESPOND_IMMIEDIA(高速响应线程),该线程就绪后会加入到就绪环头部。(就绪环概念请参考《SylixOS线程调度浅析》文档)

    if (API_ThreadSetSchedParam(thread, LW_OPTION_SCHED_FIFO,

    LW_OPTION_RESPOND_IMMIEDIA)) {

    errno = ESRCH;

    return (PX_ERROR);

    }

    图 2-2设置线程参数

  18. 启动调度器时,如图 2-3所示,第一次执行时间是不准确的,首先使用lib_clock_gettime()函数获得第一次启动时时间。等第二次执行时依然使用lib_clock_gettime()函数获得第二次启动时间,计算两次执行时间间隔;然后通过__timespecSub()函数计算时间间隔与所定周期的时间差;然后调用__timespecAdd()函数使程序以确定周期运行;这时可以确定程序运行与所定周期的时间差,最后调用nanosleep()函数使该线程睡眠此时间差时间。这样就能保证调度器自动调整时间。

    lib_clock_gettime(CLOCK_MONOTONIC, &temp); /* 获得当前时间 */

    etime = temp;

    __timespecSub(&etime, &prms->PRMS_tsSave);

    if (__timespecLeftTime(period, &etime)) { /* 执行时间超过周期 */

    lib_clock_gettime(CLOCK_MONOTONIC, &prms->PRMS_tsSave); /* 获得当前时间 */

    errno = EOVERFLOW;

    return (PX_ERROR);

    }

    temp = *period;

    __timespecSub(&temp, &etime);

    /*

    * 注意: 这里直接加上周期是为了让每次测算都是以一个固定周期律进行

    * 提高周期精度. (不使用 lib_clock_gettime())

    */

    __timespecAdd(&prms->PRMS_tsSave, period); /* 以确定周期运行 */

    return (nanosleep(&temp, LW_NULL));

    图 2-3启动调度器过程

  19. 调度器销毁时直接将RMS结构体sched_rms_t成员PRMS_iStatus置0。
  20. 示例演示

    如图 2-4 所示为RMS使用用例,设置RMS调度器时间为3秒,代码执行时间随机产生,最终测试结果为3秒打印一次。


    #include <stdio.h>

    #include <sched_rms.h>

    #include <pthread.h>

    #include <stdlib.h>

    #include <time.h>

    sched_rms_t rms;

    void process_func(void) /* 执行函数 */

    {

    srand(time(NULL)); /* 产生随机数 */

    int i = rand()%2;

    for (; i >= 0; --i) { /* 随机睡眠一段时间 */

    sleep(1);

    }

    }

    void *rms_thread ()

    {

    pthread_t tid;

    struct timespec period; /* 设置调度周期为3秒 */

    period.tv_nsec = 0;

    period.tv_sec = 3;

    tid = pthread_self(); /* 获得自身tid */

    sched_rms_init(&rms, tid); /* 初始化RMS调度器 */

    while (1) {

    if (sched_rms_period(&rms, &period) != 0) { /* 启动RMS调度器 */

    break;

    }

    fprintf(stdout, "rms thread running...\n");

    process_func();

    }

    return (NULL);

    }

    int main (int argc, char *argv[])

    {

    pthread_t tid;

    int ret;

    ret = pthread_create(&tid, NULL, rms_thread, NULL); /* 创建线程 */

    if (ret < 0) {

    fprintf(stderr, "pthread_create error.\n");

    return (-1);

    }

    pthread_join(tid, NULL);

    sched_rms_destroy(&rms); /* 销毁RMS调度器 */

    return (0);

    }

    图 2-4 使用用例

时间: 2024-10-01 07:15:08

SylixOS的RMS浅析的相关文章

SylixOS 虚拟设备文件浅析

目录 1.虚拟设备文件概述    1 2.虚拟设备文件eventfd    1 2.1    虚拟设备文件eventfd概述    1 2.2    打开虚拟设备文件eventfd    1 2.3    读取事件文件    3 2.4    写事件文件    3 3.参考文献    4 虚拟设备文件概述 Linux内核自2.6.22版本开始逐步增加了三个虚拟设备文件:eventfd.timerfd.signalfd.这三个文件让应用程序可以通过标准I/O操作的方式代替传统调用API的方式来使用

SylixOS钩子函数浅析

1 使用背景对定时器做相关配置,使得每隔时间T,触发定时器中断,可以在定时器中断处理函数处理算法,这样就可以周期性的执行特定的任务.但如果不想在定时器中断处理函数中添加算法,比如说用户只想在应用程序里面执行他们的任务,那么钩子函数就是一个不错的选择.2 钩子函数的原理本章以定时器中断为例说明SylixOS钩子的使用方法.2.1 API_InterVectorIsr函数函数原型如程序清单 2.1程序清单 2.1#include <SylixOS>irqreturn_t API_InterVect

SylixOS线程私有数据浅析

目录 1. 线程私有数据概述    1 2. 线程私有数据的相关API函数流程浅析    1 2.1    加入线程私有变量    1 2.2    删除线程私有变量    3 2.3    设置私有线程变量    6 2.4    获得线程私有变量值    8 3. 总结    10 4. 参考文献    10 线程私有数据概述 在SylixOS中为了满足多线程安全的要求,使得一种资源可以安全的被多个线程使用,采用了包括代码临界区保护和可重入性等方法.本文描述实现可重入的一种方法:线程私有数据

SylixOS 启动浅析

1.SylixOS启动概述 每个操作系统的启动都是多种多样,各有不同,SylixOS亦是如此,本文将浅析SylixOS启动层次和启动步骤两大方面. 2.SylixOS启动层次 在专用的嵌入式开发板上运行嵌入式操作系统(如SylixOS.Linux等)已经变得越来越流行,通常从一个嵌入式操作系统的软件角度来看,引导加载程序和操作系统内核便是两个重要的层次,下面就简单介绍关于SylixOS这两大层次的关键点. 2.1 层次一:Boot过程 一个裸机可执行程序的运行方法有两种: 1. 将程序代码入口放

SylixOS中pthread_cancel函数浅析

1 知识简介 1.1 概述 取消一个线程要确保该线程能够释放其所持有的任何锁.分配的内存,使整个系统保持一致性.在很多复杂情况下要保证这种正确性是有一定困难的. 一种简单的线程取消:取消线程调用一个取消线程的函数,被取消线程死亡.在这种情况下,被取消线程所持有的的资源得不到释放.取消线程负责保证被取消者处于可安全取消状态,在一个要求可靠性高的系统中,这种保证非常困难或者无法实现.这种取消称为不受限制的异步取消. 还存在另外一种更安全的线程取消机制.一个线程可以以可靠的受控制的方式向进程的其他线程

SylixOS DNS浅析

1. DNS 概述 网络通讯大部分是基于TCP/IP,而TCP/IP又基于IP地址.故计算机在网络上进行通讯时只能识别如"192.168.2.1"之类的IP地址,而无法识别域名.在访问网站时,更多的是在浏览器地址栏中输入域名,就能看到所需的页面,这是因为有一个叫"DNS服务器"的计算机自动把域名"翻译"成了相应的IP地址. DNS(Domain Name System)是"域名系统"的英文缩写,是一种组织成域层次结构的计算机和

SylixOS的信号屏蔽浅析

1.信号介绍 信号是一种软中断,用于通过异步的方式对进程进行事件通知.信号分为实时信号和非实时信号,各个进程对于信号的处理方式不一,处理方式分为三类:忽略,捕捉,执行系统默认动作.进程可以选择屏蔽某个或某些信号. 2.信号屏蔽 SylixOS可以通过sigprocmask函数对某个信号集内的信号进行屏蔽.在信号被屏蔽的期间,进程对所屏蔽的大部分信号不会进行响应,只有解除屏蔽后才会响应. 2.1 sigprocmask函数 sigprocmask函数原型如程序清单 2-1所示. 程序清单 2-1 

SylixOS线程堆栈大小浅析

目录 1. SylixOS线程.线程栈介绍    1 1.1    线程的介绍    1 1.2    线程栈的介绍    1 2. SylixOS线程栈大小的分配    1 2.1    线程.线程栈相关属性的设置    2 2.2    线程栈大小    2 2.3    线程堆栈警戒区    3 3. 总结    5 4. 参考资料    5 SylixOS线程.线程栈介绍 SylixOS是多线程操作系统,系统能够同时创建多个线程,具体最大线程数量取决于系统内存的大小以及编译SylixOS

SylixOS CAN总线报文浅析

CAN的报文格式 在总线中传送的报文,每帧由7部分组成.CAN协议支持两种报文格式,其唯一的不同是标识符(ID)长度不同,标准格式为11位,扩展格式为29位. 在标准格式中,报文的起始位称为帧起始(SOF),然后是由11位标识符和远程发送请求位(RTR)组成的仲裁场.RTR位标明是数据帧还是请求帧,在请求帧中没有数据字节. 控制场包括标识符扩展位(IDE),指出是标准格式还是扩展格式.它还包括一个保留位 (ro),为将来扩展使用.它的最后四个位用来指明数据场中数据的长度(DLC).数据场范围为0