概念

为周期性任务解决多任务调度冲突的一种非常好的方法是速率单调调度(Rate Monotonic Scheduling RMS),RMS 基于任务的周期指定优先级。
在 RMS 中,最短周期的任务具有最高优先级,次短周期的任务具有次高优先级,依次类推。当同时有多个任务可以被执行时,最短周期的任务被优先执行。如果将任务的优先级视为速率的函数,那么这就是一个单调递增函数。

接口

sylixos提供两种类型的RMS调度器接口,一个是sylixos内核自带接口,一个是POSIX标准接口,这两类都可实现周期任务,但不要混用。

sylixos内核原生接口

/*********************************************************************************************************
** 函数名称: API_RmsCreate
** 功能描述: 建立一个精度单调调度器
** 输 入  : 
**           pcName                        名字
**           ulOption                      选项
**           pulId                         Id 号
** 输 出  : 
*********************************************************************************************************/
LW_OBJECT_HANDLE  API_RmsCreate (CPCHAR             pcName,
                                 ULONG              ulOption,
                                 LW_OBJECT_ID      *pulId)
                                 /*********************************************************************************************************
** 函数名称: API_RmsCancel
** 功能描述: 指定精度单调调度器停止工作
** 输 入  : 
**           ulId                          RMS 句柄
** 输 出  : 
*********************************************************************************************************/
ULONG  API_RmsCancel (LW_OBJECT_HANDLE  ulId)
/*********************************************************************************************************
** 函数名称: API_RmsExecTimeGet
** 功能描述: 获得当前任务从调用 API_RmsPeriod() 函数到目前执行的时间,单位为: Tick.
** 输 入  : 
**           ulId                          RMS 句柄
**           pulExecTime                   运行时间
** 输 出  : 
*********************************************************************************************************/
ULONG   API_RmsExecTimeGet (LW_OBJECT_HANDLE  ulId, ULONG  *pulExecTime)
/*********************************************************************************************************
** 函数名称: API_RmsPeriod
** 功能描述: 指定精度单调调度器开始按固定周期工作
** 输 入  : 
**           ulId                          RMS 句柄
**           ulPeriod                      程序段执行周期
** 输 出  : 
*********************************************************************************************************/ 
ULONG  API_RmsPeriod (LW_OBJECT_HANDLE  ulId, ULONG  ulPeriod)
/*********************************************************************************************************
** 函数名称: API_RmsStatus
** 功能描述: 获得精度单调调度器的状态
** 输 入  : 
**           ulId                          RMS 句柄
**           pucStatus                     名字缓冲区    可以为 NULL
**           pulTimeLeft                   等待剩余时间  可以为 NULL
**           pulOwnerId                    所有者 ID     可以为 NULL
** 输 出  : 
*********************************************************************************************************/
ULONG  API_RmsStatus (LW_OBJECT_HANDLE  ulId,
                      UINT8            *pucStatus,
                      ULONG            *pulTimeLeft,
                      LW_OBJECT_HANDLE *pulOwnerId)
/*********************************************************************************************************
** 函数名称: API_RmsDeleteEx
** 功能描述: 删除精度单调调度器
** 输 入  : 
**           pulId                         RMS 句柄指针
**           bForce                        强制删除
** 输 出  : 
*********************************************************************************************************/
ULONG  API_RmsDeleteEx (LW_OBJECT_HANDLE   *pulId, BOOL  bForce)

POSIX标准接口

作为 POSIX 的扩展,SylixOS 提供了下面一组函数来实现 POSIX RMS 调度器,相比之前的 RMS 实现,下面的函数更加易用且时间精度更高(纳秒级)。

/*********************************************************************************************************
** 函数名称: sched_rms_init
** 功能描述: 初始化 RMS 调度器
** 输 入  : prms      RMS 调度器
**           thread    需要调用 RMS 的线程.
** 输 出  : 是否初始化成功
*********************************************************************************************************/
int  sched_rms_init (sched_rms_t  *prms, pthread_t  thread)
/*********************************************************************************************************
** 函数名称: sched_rms_destroy
** 功能描述: 删除 RMS 调度器
** 输 入  : prms      RMS 调度器
** 输 出  : 是否删除成功
*********************************************************************************************************/
int  sched_rms_destroy (sched_rms_t  *prms)
/*********************************************************************************************************
** 函数名称: sched_rms_period
** 功能描述: 删除 RMS 调度器
** 输 入  : prms      RMS 调度器
**           period    RMS 周期
** 输 出  : 0 表示正确
**           error == EINTR    表示被信号激活.
*********************************************************************************************************/ 
int  sched_rms_period (sched_rms_t  *prms, const struct timespec *period)

调用 sched_rms_init 函数将初始化参数 prms 指定的 RMS 调度器,与 Lw_Rms_Create函数不同的是,前者由应用程序创建一个 sched_rms_t 类型的 RMS 调度器,然后调用sched_rms_init 函数来初始化这个调度器,也就是说,此调度器将由应用程序创建和销毁,而后者创建的 RMS 调度器则由内核管理,也即应用程序不会直接管理所使用的调度器。

例程

SylixOS原生接口例程

#include <sched_rms.h>
#include <pthread.h>
/*********************************************************************************************************
** 函数名称: rms_thread
** 功能描述: 线程函数
** 输 入  : arg  传入的参数
** 输 出  : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
void *rms_thread (void *arg)
{
    LW_OBJECT_HANDLE  hRms;
    ULONG             ulPeriod = 5 * CLOCKS_PER_SEC;
    struct timespec   tv;

    hRms = API_RmsCreate("rmstest", 0, NULL);
    while (1) {
        if (API_RmsPeriod(hRms, ulPeriod) != 0) {
            fprintf(stderr, "sched_rms_period error\n");
            break;
        }

        lib_clock_gettime(CLOCK_MONOTONIC, &tv);
        fprintf(stdout, "[%16llu]\n", (tv.tv_sec * 1000000 + tv.tv_nsec / 1000));

        sleep(1);
    }

    return  (NULL);
}
/*********************************************************************************************************
** 函数名称: main
** 功能描述: 主函数
** 输 入  : argc,argv
** 输 出  : ERROR
** 全局变量:
** 调用模块:
*********************************************************************************************************/
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);

    return  (0);
}

POSIX标准接口例程

#include <sched_rms.h>
#include <pthread.h>
/*********************************************************************************************************
  全局变量定义
*********************************************************************************************************/
sched_rms_t     rms;
/*********************************************************************************************************
** 函数名称: rms_thread
** 功能描述: 线程函数
** 输 入  : arg  传入的参数
** 输 出  : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
void *rms_thread (void *arg)
{
    struct timespec   *period = (struct timespec *)arg;
    struct timespec    tv;


    sched_rms_init(&rms, pthread_self());
    while (1) {
        if (sched_rms_period(&rms, period) != 0) {
            fprintf(stderr, "sched_rms_period error\n");
            break;
        }
        lib_clock_gettime(CLOCK_MONOTONIC, &tv);
        fprintf(stdout, "[%16llu]\n", (tv.tv_sec * 1000000 + tv.tv_nsec / 1000));

        sleep(1);
    }

    return  (NULL);
}
/*********************************************************************************************************
** 函数名称: main
** 功能描述: 主函数
** 输 入  : argc,argv
** 输 出  : ERROR
** 全局变量:
** 调用模块:
*********************************************************************************************************/
int main (int argc, char *argv[])
{
    pthread_t           tid;
    int                 ret;
    struct timespec     period;

    period.tv_nsec = 0;
    period.tv_sec  = 5;

    ret = pthread_create(&tid, NULL, rms_thread, (void *)&period);
    if (ret < 0) {
        fprintf(stderr, "pthread_create error.\n");
        return  (-1);
    }

    pthread_join(tid, NULL);
    sched_rms_destroy(&rms);

    return  (0);
}

执行结果

gRPC 时延_sylixos