RTEMS是以线程为基本调度单位的,调度算法基于优先级的抢占式线程调度,支持256个线程优先级。当然RTEMS值hi创建同等优先级线程,相同优先级的线程采用时间片轮转调度。调度器寻找下一个最高优先级就绪线程的时间是o(1),这是实时性得到保障的一个关键机制。

为了增强对用户应用需求的可扩展性,rtems实现了基于线程的任务扩展机制,可在创建任务、上下文切换或者删除任务等系统事件发生时插入用户指定的函数(称为钩子函数,hook函数),以完成用户设定的特殊功能。

对于RTEMS这样的基于抢占式和优先级策略调度的os而言,为保证硬实时特性,需要选择一个合适的调度算法,静态调度算法-速率单调调度RMS是为周期性任务解决多任务调度的一种很好的算法。

本文会先介绍核心层的thread handler组件与调度实现,然后对RMS算法在RTEMS上的实现进行分析。

核心层的thread handler组件:

RTEMS的调度相对于通用操作系统而言较为简单,主要是基于线程的优先级进行的,除了对于优先级反转问题需要在运行时改变线程的优先级外,其他情况下不会对线程的优先级修改。

thread handler组件提供了thread_control结构体和以此配套的一组基本线程管理数据结构和管理函数,涉及线程初始化,线程启动,线程暂停,线程恢复,线程切换等。不同的高层API接口实现只是对这些结构和函数进行封装,这样线程管理就可以分为两层,方便API接口进行拓展。

1.线程控制块(TCB)

thread control block是thread handler组件对线程的静态进本情况和动态运行变化过程的描述,其包含了与线程运行管理所需要的所有信息集合,是线程存在的唯一标志。线程的创建主要体现在为该线程生成一个TCB,而线程终止则体现在回收其TCB。

TCB定义在cpukit/score/include/rtems/score/thread.h中,如下:

/***  This structure defines the Thread Control Block (TCB).*/
struct Thread_Control_struct {/** This field is the object management structure for each thread. */Objects_Control          Object;/** This field is used to enqueue the thread on RBTrees. */RBTree_Node              RBNode;/** This field is the current execution state of this thread. */States_Control           current_state;/** This field is the current priority state of this thread. */Priority_Control         current_priority;/** This field is the base priority of this thread. */Priority_Control         real_priority;/*** @brief Thread priority control.*/Thread_Priority_control  Priority;/** This field is the number of mutexes currently held by this thread. */uint32_t                 resource_count;/** This field is the blocking information for this thread. */Thread_Wait_information  Wait;/** This field is the Watchdog used to manage thread delays and timeouts. */Watchdog_Control         Timer;
#if defined(RTEMS_MULTIPROCESSING)/** This field is the received response packet in an MP system. */MP_packet_Prefix        *receive_packet;
#endif/*================= end of common block =================*/#if defined(RTEMS_SMP)/*** @brief Thread lock control.*/Thread_Lock_control Lock;
#endif#ifdef __RTEMS_STRICT_ORDER_MUTEX__/** This field is the head of queue of priority inheritance mutex*  held by the thread.*/Chain_Control            lock_mutex;
#endif
#if defined(RTEMS_SMP)/*** @brief Resource node to build a dependency tree in case this thread owns* resources or depends on a resource.*/Resource_Node            Resource_node;
#endif
#if defined(RTEMS_MULTIPROCESSING)/** This field is true if the thread is offered globally */bool                                  is_global;
#endif/** This field is true if the thread is preemptible. */bool                                  is_preemptible;/*** @brief Scheduler related control.*/Thread_Scheduler_control              Scheduler;#if __RTEMS_ADA__/** This field is the GNAT self context pointer. */void                                 *rtems_ada_self;
#endif/** This field is the length of the time quantum that this thread is*  allowed to consume.  The algorithm used to manage limits on CPU usage*  is specified by budget_algorithm.*/uint32_t                              cpu_time_budget;/** This field is the algorithm used to manage this thread's time*  quantum.  The algorithm may be specified as none which case,*  no limit is in place.*/Thread_CPU_budget_algorithms          budget_algorithm;/** This field is the method invoked with the budgeted time is consumed. */Thread_CPU_budget_algorithm_callout   budget_callout;/** This field is the amount of CPU time consumed by this thread*  since it was created.*/Thread_CPU_usage_t                    cpu_time_used;/** This field contains information about the starting state of*  this thread.*/Thread_Start_information              Start;Thread_Action_control                 Post_switch_actions;/** This field contains the context of this thread. */Context_Control                       Registers;
#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )/** This field points to the floating point context for this thread.*  If NULL, the thread is integer only.*/Context_Control_fp                   *fp_context;
#endif/** This field points to the newlib reentrancy structure for this thread. */struct _reent                        *libc_reent;/** This array contains the API extension area pointers. */void                                 *API_Extensions[ THREAD_API_LAST + 1 ];#if !defined(RTEMS_SMP)/** This field points to the set of per task variables. */rtems_task_variable_t                *task_variables;
#endif/*** This is the thread key value chain's control, which is used* to track all key value for specific thread, and when thread* exits, we can remove all key value for specific thread by* iterating this chain, or we have to search a whole rbtree,* which is inefficient.*/Chain_Control           Key_Chain;/*** @brief Thread life-cycle control.** Control state changes triggered by thread restart and delete requests.*/Thread_Life_control                   Life;Thread_Capture_control                Capture;/*** @brief Variable length array of user extension pointers.** The length is defined by the application via <rtems/confdefs.h>.*/void                                 *extensions[ RTEMS_ZERO_LENGTH_ARRAY ];
};

其中解释几个重要的成员变量:

object是线程作为对象而存在的对象管理结构,也就是说TCB结构是作为一个对象。

real_priority和current_priority是线程的基础优先级和当前运行的优先级。

resource_count是代表线程获取到的资源(互斥量)数量,是为了实现优先级继承算法和优先级天花板算法而设计的。

cpu_time_budget是分配给线程的时间片,而budget_algorithm是用来管理该时间片的算法。RTEMS支持如下四种时间片算法配置:

a. THREAD_CPU_BUDGET_ALGORITHM_NONE //不使用budget算法

b. THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE //线程切换时重新设置时间片

c. THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE //线程时用完时间片才重置

d. THREAD_CPU_BUDGET_ALGORITHM_CALLOUT //时间片用完时调用回调函数

通常在嵌入式系统中,为了节省内粗怒,内核所支持的最大线程数量是静态配置好的,在RTEMS中是通过宏定义完成的:
#define CONFIGURE_MAXIMUM_TASKS            1
通常是在testsuites例子程序的init.c文件中。
这样在系统初始化时可以根据线程的个数来为TCB分配内存,构成一个空闲的线程控制块链,创建线程时从该链上取出空闲TCB进行初始化,删除线程时,将该TCB返回到空闲链中。

2.线程调度机制

RTEMS中基本采用可抢占的调度方式,为了实现更加灵活的调度手段,RTEMS提供四种机制允许用户对线程调度进行干预:
a.用户执行线程优先级(可动态修改)
b.线程抢占式控制(该线程是否会被抢占):用户可通过改变TCB中抢占模式标志(RTEMS_PREEMPT_MASK)影响调度的策略。若抢占位置为无效,那么线程就不会被抢占,除非线程结束或者被阻塞。否则就算有较高的优先级线程就绪,线程也不会被抢占。
c.线程时间片控制:基于优先级的时分复用,也称为轮转调度,如果时分复用状态位通过RTEMS_TIMESLICE使能,那么RTEMS将会限制线程在处理器中的运行时间,若到达该线程的运行时间片,将会被其他线程取代。但是当一个较高的优先级线程就绪时,会立即抢占处理器中低优先级的线程,即使线程还没用光其整个时间片。 也就是说时间片控制适用于同等优先级线程之间的调度。
d.主动放弃处理器,程序员可使用rtems_task_wake_after函数主动放弃对CPU的占用。

3.线程上下文

运行的线程变为就绪或者阻塞时,都需要保存当前进程的上下文。线程的上下文是和硬件的体系结构密切相关,RTEMS中,ARM的上下文定义如下:

typedef struct {
#if defined(ARM_MULTILIB_ARCH_V4)uint32_t register_cpsr;uint32_t register_r4;uint32_t register_r5;uint32_t register_r6;uint32_t register_r7;uint32_t register_r8;uint32_t register_r9;uint32_t register_r10;uint32_t register_fp;uint32_t register_sp;uint32_t register_lr;
#elif defined(ARM_MULTILIB_ARCH_V6M) || defined(ARM_MULTILIB_ARCH_V7M)uint32_t register_r4;uint32_t register_r5;uint32_t register_r6;uint32_t register_r7;uint32_t register_r8;uint32_t register_r9;uint32_t register_r10;uint32_t register_r11;void *register_lr;void *register_sp;uint32_t isr_nest_level;
#elsevoid *register_sp;
#endif
#ifdef ARM_MULTILIB_HAS_THREAD_ID_REGISTERuint32_t thread_id;
#endif
#ifdef ARM_MULTILIB_VFPuint64_t register_d8;uint64_t register_d9;uint64_t register_d10;uint64_t register_d11;uint64_t register_d12;uint64_t register_d13;uint64_t register_d14;uint64_t register_d15;
#endif
#ifdef RTEMS_SMPvolatile bool is_executing;
#endif
} Context_Control;

TCB中的Registers就是上下文的变量。

4.线程的优先级管理

每个优先级的就绪的线程都是一个FIFO链表,TCB中会包含该链表,便于线程调度时的操作。_thread_ready_chain就是由各个优先级的FIFO构成的数组,这是一个全局变量。

chain_control结构是对FIFO链表进行管理的数据结构,包含了链表的头和尾,这样可以很快确定每个优先级的第一个线程和最后一个。但问题在于,不容易确定下一个优先级最高的线程,如果切换出来的线程所在的优先级只有一个就绪线程,那么就需要在_thread_ready_chain数组中找到优先级最高的就绪线程,这是一个耗时的操作,因此RTEMS采用位图的方法解决了这个问题。它把256个优先级分为16*16,这样的话,就相当于两个16位整数就可以表示了,也就是两个16位长的二进制数组。这样提高了搜索速度。这样一个priority优先级可以分为major(priority/16)和minor(priority%16)两部分。major*16+minor.

RTEMS中的RMS实时调度

RMS速率单调调度算法基于以下假设:

a. 所有任务都是周期任务

b. 任务的相对截止时间等于任务周期

c.任务在每个周期的计算时间都相等

d.任务之间不进行通信,也不需要同步,是独立的

e.任何可以在计算的任何位置被抢占

任务的优先级和任务的周期表吓你为单调函数关系,任务周期越短,任务优先级越高。静态是指任务的优先级是事前确定的,在任务运行过程中不会改变。

关键数据结构

typedef struct {/** This field is the object management portion of a Period instance. */Objects_Control                         Object;/*** @brief Protects the rate monotonic period state.*/ISR_LOCK_MEMBER(                        Lock )/** This is the timer used to provide the unblocking mechanism. */Watchdog_Control                        Timer;/** This field indicates the current state of the period. */rtems_rate_monotonic_period_states      state;/*** @brief A priority node for use by the scheduler job release and cancel* operations.*/Priority_Node                           Priority;/*** This field contains the length of the next period to be* executed.*/uint32_t                                next_length;/*** This field contains a pointer to the TCB for the thread* which owns and uses this period instance.*/Thread_Control                         *owner;/*** This field contains the cpu usage value of the owning thread when* the period was initiated.  It is used to compute the period's* statistics.*/Timestamp_Control                       cpu_usage_period_initiated;/*** This field contains the wall time value when the period* was initiated.  It is used to compute the period's statistics.*/Timestamp_Control                       time_period_initiated;/*** This field contains the statistics maintained for the period.*/Rate_monotonic_Statistics               Statistics;/*** This field contains the number of postponed jobs.* When the watchdog timeout, this variable will be increased immediately.*/uint32_t                                postponed_jobs;/***  This field contains the tick of the latest deadline decided by the period*  watchdog.*/uint64_t                                latest_deadline;
}   Rate_monotonic_Control;

Watchdog_Control 是和这个结构体关联的定时器

rtems_rate_monotonic_period_states     RMS的状态

关键实现函数

对于RMS,RTEMS提供了以下API:

rtems_rate_monotonic_create 创建一个RMS

rtems_rate_monotonic_cancel 取消一个RMS

rtems_rate_monotonic_delete 删除一个RMS

rtems_rate_monotonic_get_status 获得RMS状态

rtems_rate_monotonic_period 核心函数,用于启动一个周期,在这里发生RMS状态转换

RTEMS中RMS实现算法如下:

程序调用rtems_rate_monotonic_period ,此时系统认为线程开始一项周期任务,且周期长度为length,记这一时刻time_at_period。当线程的执行流到达下一个rtems_rate_monotonic_period语句时(在一般程序中,是回到之前调用的那句rtems_rate_monotonic_period ),系统会判断从time_at_period开始到现在是否经过了length个tick,如果超过了,重新开始一个周期。通常是不会超过的,此时这个线程会被阻塞,等待下一周期的开始,知道系统时刻确实到达time_at_period+length。线程会被唤醒。

应用举例:

RTMES/testsuites/sptests/sp32中包含了对RMS的测试用例。其功能是让任务运行五个确定的周期,在每个周期的开始和结束记录时间,然后相减,看是否与指定的周期长度相等。

RTEMS线程调度算法(RMS)详解相关推荐

  1. async spring 默认线程池_Spring boot注解@Async线程池实例详解

    这篇文章主要介绍了Spring boot注解@Async线程池实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 从Spring3开始提供了@A ...

  2. InheritableThreadLocal类原理简介使用 父子线程传递数据详解 多线程中篇(十八)...

    上一篇文章中对ThreadLocal进行了详尽的介绍,另外还有一个类: InheritableThreadLocal 他是ThreadLocal的子类,那么这个类又有什么作用呢? 测试代码 publi ...

  3. openstack ice自定义调度算法项目详解(horizon、novaclient、api、scheduler、db、自定义数据库)

    原文转自:openstack ice自定义调度算法项目详解(horizon.novaclient.api.scheduler.db.自定义数据库) 第一部分:页面层即horizon与novaclien ...

  4. C++11多线程第三篇:线程传参详解,detach()大坑,成员函数做线程参数

    文章目录 3.1 传递临时对象作为线程参数 3.1.1 要避免的陷阱(解释1) 3.1.2 要避免的陷阱(解释2) 3.1.3 总结 3.2 临时对象作为线程参数进一步详解 3.2.1 线程id概念 ...

  5. python线程池原理_Python定时器线程池原理详解

    这篇文章主要介绍了Python定时器线程池原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 定时器执行循环任务: 知识储备 Timer(int ...

  6. java 线程同步的list_java集合框架线程同步代码详解

    List接口的大小可变数组的实现.实现了所有可选列表操作,并允许包括null在内的所有元素.除了实现List接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小.(此类大致上等同于Vector ...

  7. 线程池源代码详解,参数详解

    线程池源代码详解,参数详解 ThreadPoolExecutor 构造函数源代码 public ThreadPoolExecutor(int corePoolSize, int maximumPool ...

  8. Java线程池ThreadPool详解

    Java线程池ThreadPool详解 1. 线程池概述 1.1 线程池简介 1.2 线程池特点 1.3 线程池解决问题 2. 线程池原理分析 2.1 线程池总体设计 2.6 线程池流转状态 2.2 ...

  9. python 线程等待_详解python多线程之间的同步(一)

    引言: 线程之间经常需要协同工作,通过某种技术,让一个线程访问某些数据时,其它线程不能访问这些数据,直到该线程完成对数据的操作.这些技术包括临界区(Critical Section),互斥量(Mute ...

最新文章

  1. 送书 | 2020年新一天,用这本书开启你的NLP学习之路!
  2. 中国黑客自揭黑色产业链条:做病毒一定要低调
  3. c语言编程任意矩阵相乘,c语言矩阵相乘
  4. Swift URL含有中文的处理
  5. 在代码中向ReportViewer动态添加数据源
  6. 计算机无法进入桌面怎么备份,无法进入系统如何正常备份数据?
  7. AIX 磁盘和文件系统
  8. [Java基础]字节,字符打印流
  9. 前端学习(2752):global全局设置
  10. mysql语句怎么记_Mysql常用语句(记一下,免得忘)
  11. 在系统中用etcd实现服务注册和发现
  12. LeetCode(404)——左叶子之和(JavaScript)
  13. Java并发编程:并发容器之ConcurrentHashMap(转载)
  14. php能做什么程序,PHP 能做什么?
  15. 软件设计文档国家标准—软件需求说明书(GB856T——88)
  16. 文献阅读笔记之 - - 48V锂电池管理系统的设计与实现(贾小龙)
  17. flash学习者不要错过-视频教程打包下载
  18. 使用ArcMap 生成TPK和geodatabase包
  19. shell命令以及运行原理和Linux权限
  20. 【IO专栏】Java OIO NIO通信对比分析【002】

热门文章

  1. 哎呀看ted的演讲视频_设计师必看的10部TED影片
  2. 微信公众号常见问题~1024
  3. layui表格下拉选择、日期选择
  4. React Fiber详解
  5. React Fiber架构原理剖析
  6. java rowmapper 通用实现_java-在RowMapper中使用查询
  7. 世界上最高效的笔记方法(改变你那老版的记笔记方法吧)
  8. oracle存储过程报错 跳过,oracle调试存储过程的过程详解
  9. MP4 FLASH等播放代码
  10. python 标准库 excel_超全整理|Python 操作 Excel 库 xlwings 常用操作详解!