一、循环调度任务
对于具有相同优先级的任务,Xenomai调度程序同时支持FIFO调度和循环策略。循环策略类似于分时操作系统依次运行每个活动进程以获得其时间份额(其“时间片”)。
FIFO调度,任务只抢占优先级较低的任务;它从不抢占优先级相同或较低的任务。当多个具有相同优先级的任务准备运行时,首先在调度程序的等待队列中排队的任务将首先运行(遵循FIFO顺序)。只有当第一个任务就绪时,调度程序才能从等待队列中执行第二个等待任务。
循环调度算法试图在具有相同优先级的所有就绪任务之间实现公平调度。如果没有循环调度,单个任务就可以不阻塞的通过,从而从不给其他同等优先级的任务运行的机会来篡夺处理器。就是说实现这种调度,会使处理器平均分配所设定的时间给相同优先级任务去运行。
二、实现循环调度常用的API
1、更改当前任务模式
每个实时任务都有一组内部标志,用于确定几个操作条件。rt_task_set_mode()接受一个模式位的位掩码来清除当前任务的相应模式,并设置另一个位掩码来启用它们。在更改之前有效的模式位可以根据请求返回。
int rt_task_set_mode (
int clrmask,
int setmask,
int * mode_r
)
clrmask : 在应用setmask之前,为当前任务清除模式位的位掩码。
setmask : 为当前任务设置的模式位的位掩码。
mode_r :如果该非空,则mode_r必须是指向内存位置的指针,该内存位置将在使用前T_LOCK导致当前任务锁定当前CPU上的调度器,防止该CPU上的所有非自愿任务切换。清除此位将解锁调度程序。
若将setmask设置为T_LOCK将会导致每个任务锁定,不会执行同等优先级的循环。
若要设置为循环调度模式应将改为设置为XNRRB。
rt_task_set_mode(0,XNRRB,NULL);/*允许当前任务执行循环操作*/
当运行在Cobalt时(需要在实时内核与非实时内核间切换时):
T_WARNSW使SIGDEBUG信号在切换到辅助模式时被发送到当前任务。该特性对于检测到Linux域的不需要的迁移非常有用。
请求Xenomai在切换到辅助模式时想我们发出信号
rt_task_set_mode(0,T_WARNSW,NULL);
T_CONFORMING可以将当前 Alchemy 任务切换到首选的实时模式。此开关的唯一有意义的用途是强制实时任务返回主模式。任何其他用途都是无效的。
若将setmask设置为T_CONFORMING,将会把任务设置为设置Xenomai任务执行模式。
rt_task_set_mode(0,T_CONFORMING,NULL);
一般不会使用此标志位,强制执行可能会产生会多问题,仅用于覆盖基于Alchemy接口的中间件代码中的罕见用例
若要清除设置的这些标志位,只需在clrmask设置相应的标志位即可。
2、设置任务的循环量
int rt_task_slice (
RT_TASK * task,
RTIME quantum
)
task : 任务描述符号,如果任务为空。任务必须属于当前进程,且调用者必须是Alchemy 任务
quantum : 进行时间切片,任务的循环量子。
将循环时间片间隔值设置为量子时钟节拍(以ns为单位)。这个时间间隔是每个任务在将处理器交给另一个同等优先级的任务之前允许运行的时间量。这些函数只需要调用一次。
三、例子
1、具有相同优先级的三个任务在控制台上打印其任务ID
程序及结果如下:
程序5a:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <alchemy/task.h>
#include <alchemy/sem.h>
#include <alchemy/timer.h>
#define NTASKS 3
RT_TASK demo_task[NTASKS];
RT_SEM mysync;
#define EXECTIME 1e8 // execution time in ns
#define SPINTIME 1e7 // spin time in ns
void demo(void