0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

使用C语言setjmp库函烽实现查询式协作多任务系统的设计

牵手一起梦 来源:单片机与嵌入式系统应用 作者:胡道徐 2020-10-04 17:46 次阅读

讨论一个利用标准C语言setjmp库函烽实现查询式协作多任务系统,给出完整的内核和样例程序并对源代码进行说明。该系统具有简单易用的特点,只需要编写存取堆栈指针的宏就可方便地移植到新的平台上。文章详述了系统的优缺点,讨论一些性能扩展的方法。该内核适用于中小规模的嵌入式软件

本文介绍的是利用标准C语言setjmp库函数实现的具备此特点的协作式多任务系统。从本质上讲,实时多任务操作系统应该具备按照优先级抢占调度的内核。然而,在实际应用中,抢中式的多任务某种程序上带来了用户程序设计时数据保护的困难,并且,具备抢占功能的多任务内核设计时困难也比较多,这会增加操作系统自身的代码,也使它在小资源单片机系统中应用较少;而协作多任务系统的调度只在用户指定的时机发生,这会大大简化内核和用户系统的设计,尤其本文实现的系统通过条件查询来放弃CPU,既符合传统单片机程序设计的思维,又带来了多任务、模块化、可重入的编程便利。

Setjmp是标准C语言库函数的组成部分,它可以实现程序执行中的远程转操作。具体来说,它可以在一个函数中使用setjmp来初始化一个全局标号,然后只要该函数未曾返回,那么在其它任何地方都可以通过longjmp调用来跳转到setjmp的下一条语句执行。实际上,setjmp函数将发生调用处的局部环境保存在一个jmp_buf的结构当中,只要主调函数中对应的内存未曾释放(函数返回时局部内存就失效了),那么在调用longjmp的时候就可以根据已保存的jmp_buf参数恢复到setjmp的地方执行。我们的系统中就是分析了setjmp标准库函数的特点,以简单的方式实现了协作式多任务。

1 演示程序

为了便于理解,首先给出多任务演示程序的源代码。这个程序演示了协作式多任务切换、任务的动态生成、多任务共用代码等功能,一共使用了init_coos初始化根任务(也就是C语言main函数)、creat_task创建新任务和WAITFOR查询条件这3个基本的系统调用。由于面向嵌入式系统,因而程序不会中止并且运行中也没有进行任何输出,需要借助适合的调试工具来理解多任务系统的运行。

使用C语言setjmp库函烽实现查询式协作多任务系统的设计

while(1){

WAITFOR(cnt= =8);

while(i++argc);

test=0x55;

/*使用函数调用在子程序中测试WAITFOR*/

subfunc();

while(i++15);

cnt=0;

}

}

void subfunc(void){

int i;

WAITFOR(cnt

/*选择X86_VC6,X86_BC5,AVR_GCC或M68H_SDS.*/

#define X86_VC6

#define MAX_TSK 10

typedef struct {

void (*entry)(int argc,void *argv);

jmp_buf env;

int argc;

void *argv;

}TVB;

extern TCB tcb[MAX_TSK];

extern int task_num,tskid;

void init_coos(int mainstk);

int creat_tsk(void(*entry)(int argc,void *argv),int argc,void *argv,int stksize);

#define WAITFOR(condition)do{

setjmp(tcb[tskid].env);

if(!(condition)){

tskid++;

if(tskid》=task_num)tskid=0;

longijmp(tcb[tskid].env,1);

}

}while(0)

(2)co-os.c文件清单

#include “co-os.h”

#if defined(X86_VC6)||defined(X86_BC5)

#define SAVE_SP(p) _asm mov p,esp

#define RESTORE_SP(p) _asm mov esp,p

#elif defined(AVR_GCC)

#include

#define SAVE_SP(p) p=(int*)SP

#define RESTORE_SP(p) SP=(int)p

#elif defined(M68K_SDS)

#define SAVE_SP(p) asm(“MOVE.L A7,{”#p“}”)

#define RESTORE_SP(p) asm(“MOVE.L {”#p“},A7”)

#endif

TCB tcb[MAX_TSK];

Int task_num=1;

Int tskid;

Static int stktop,oldsp;

Void init_coos(int mainstk){

SAVE_SP(stktop);

stktop=stktop+sizeof(void(*)(void))/sizeof(int)

-(mainstk+sizeof(int)-1)/sizeof(int);

}

int creat_tsk(void(*entry)(int argc,void *argv),

int argc,void *argv,int stksize){

if(task_num》=MAX_TSK)terurn-1;

SAVE_SP(oldsp);

RESTORE_SP(stktop);

If(!setjmp(tcb[task_num].env)){

RESTORE_SP(oldsp);

tcb[task_num].entry=entry;

tcb[task_num].argc=argc;

tcb[task_num].argv=argv;

task_num++;

stktop-=(stksize+sizeof(int)-1)/sizeof(int);

}

else tcb[tskid].entry(tcb[tskid].argc,tcb[tskid].argv);

return 0;

}

3 代码说明

任务代码通过执行setjmp设置本任务下次查询时的返回点,然后在等待条件放弃掉CPU跳转到下一任务的返回点处执行。如此周而复始,让各任务都获得轮转运行的机会,也要求各任务都需要主动通过等待条件的方式放弃掉CPU。系统中除了中断服务程序之外,所有任务都是平等的,都应该遵循同样的规则和其它任务一起协作运行。基本系统中没有设计杀死任务的调用,这要求各任务都应当设计成某种形式的无限循环。

任务中等待的条件可以是任务复杂的表达式或都函数调用,也可以是中断服务程序设置的全局变量(注意加volatile定义)。一般在任务执行时会让下次等待的条件不再满足,避免某个任务一直霸占CPU将系统饿死。在嵌入式软件中还经常会遇到任务定时启动和超时等待在I/O操作上,在我们的系统中可以维护一个时间计数器,只需在适当的地方记录时刻,然后在任务查询条件中判断当前计数器和记录时刻之间的差值就可以了。

内核实现的代码则相当简法。由于主要的保护和恢复任务现场的工作都由C语言标准库setjmp实现了,我们就只需要操纵一下堆栈指针防止不同的任务使用了重叠的局部环境,这个工作在初始化和创建任务的时候通过预定义的两个宏来实现。在init_coos函数中,记录了主任务(main函数)保留mainstk字节堆栈后的新栈顶位置(stktop),然后在每次creat_task时都根据要求为每个任务保留stksize字节的堆栈并重新计算下一个stktop。在creat_task函数中利用了setjmp函数的返回值(直接返回时为0,longjmp跳转返回时非0),使得一方面creat_task能正常回到调用者,又让下次轮转到新任务时能够找到创建时的入口。

co-os.h中定义的WAITFOR使用了一个do{…while(0)实现多语句宏的C语言小技巧,这样能保证在任何情况下WAITFOR都可以如单条语句一样在源程序中使用,需要担心多了或者少了大括弧破坏if/else匹配之类的问题,并且,所有的编译器都会优化掉这个假循环。

为了尽量使程序简单并说明问题,以上代码中没有考虑中断相关的数据保护问题。实际运行的系统中,如果首先写堆栈指针不能一步完成(如AVR这样的8位机),那么,在写操作正在进行的时候绝对不能允许中断;另外,在任务中查询的条件如果和中断有关,那么也必须考虑数据的完整性。

4 性能分析

所有的协作式多任务系统中任务切换时间都和用户代码(是否长期占用CPU)、就绪时刻有关,比标准系统略差的是,我们的简单系统中不支持任务优先级,并且完成一轮查询调度的时间还和任务数目有关。这也是为了达到简单和可移植性目标而不得已作出的牺牲。在各任务间切换查询条件通过C语言标准库函数longjmp实现,一般来讲longjmp函数要从内存中恢复大部分CPU寄存器,执行它也需要若干条指令的时间。

为了面向嵌入式系统应用,任务控制块(TCB)采用静态数组来实现,这样要求预先确定系统的最大任务数(co-os.h中的MAX_TSK)。如果需要,也可以通过环波链表来动态管理任务控制块(TCB),这时可以简单实现任务的动态创建和删除,并且通过指针来访问TCB也要比通过下标(tskid)略快一点。

在某些情况下,如果在中断返回后需要执行某关键任务,可以考虑通过设置“高级中断”的方法来实现。具体地讲,就是在中断返回前改变返回地址到某函数入口(“高级中断服务程序”),同时保留原返回地址到堆栈中,这样在“高级中断服务程序”完成后执行return就又回到了正常的多任务查询流程。使用“高级中断”时要注意现场保护的衔接,并且这种技巧显然和CPU和体系结构有关。

5 结论

setjmp是标准C语言中用于远程跳转的库函数,利用它可方便实现一个简单易移植的协作式多任务系统。该系统功能完备、编程简单、易于学习,适合一些中小规模的嵌入式软件使用;并且,以此为基础,还可以用一些与平台相关的编程技巧提高其实时性和灵活性。

责任编辑:gt

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    5998

    文章

    43963

    浏览量

    620691
  • 操作系统
    +关注

    关注

    37

    文章

    6274

    浏览量

    121861
  • 代码
    +关注

    关注

    30

    文章

    4554

    浏览量

    66724
收藏 人收藏

    评论

    相关推荐

    setjmp构建简单协作多任务系统

    setjmp构建简单协作多任务系统摘要:讨论一个利用标准C
    发表于 10-06 16:12

    实时多任务操作系统

    设计的高效率实时多任务内核,优秀商品化的RTOS可以面对几十个系列的嵌入处理器MPU、MCU、DSP、SOC等提供类同的API接口,这是RTOS基于设备独立的应用程序开发基础。因此基于RTOS上的C
    发表于 08-12 14:31

    setjmp构建简单协作多任务系统

    longjmp的时候就可以根据已保存的jmp_buf参数恢复到setjmp的地方执行。我们的系统中就是分析了setjmp标准库函数的特点,以简单的方式实现
    发表于 12-07 15:55

    分享Arduino C语言模拟 纯宏定义 轻量级多线程以及学习资料

    Protothreads是一种针对C语言封装后的宏函数,为C语言模拟了一种无堆栈的轻量线程环境,能够
    发表于 10-31 11:13

    RTOS中的多任务切换的相关资料分享

    浅谈RTOS中的多任务切换(基于UC/OS iii)文章目录浅谈RTOS中的多任务切换(基于UC/OS iii)一. 简介二.主要变量1.全局变量2.局部变量三.主要函数1.C语言函数
    发表于 12-06 07:08

    多任务编程多任务处理是指什么

    嵌入Linux应用编程-多任务编程多任务处理是指用户可在同一时间内运行多个应用程序,每个正在执行的应用程序被称为一个任务。Linux就是一个支持
    发表于 12-22 08:30

    setjmp、longjmp原理探究及实现

    setjmp、longjmp原理探究及实现一、原理1、实验2、猜想二、实现三、调用四、总结一、原理C语言中包含头文件即可
    发表于 01-25 07:08

    MCU是怎样用c语言实现查询红外解码的

    红外的编码格式是怎样的?MCU是怎样用c语言实现查询红外解码的?
    发表于 02-25 07:44

    如何去实现一种基于ARM9的多任务抢占调度器设计

    调度器的功能。虽然不能称为操作系统,但已体现了小型嵌入操作系统的精髓。OS代码不到1.5K,核心函数只有几个,思路简单明了。比起 UCOS,更适合用作多任务
    发表于 04-14 09:14

    多任务系统中的堆栈使用

    多任务系统运行过程中,此堆栈将专门用于中断和异常处理程序。多任务启动后,C堆栈会丢失,导致嵌入应用中可用的RAM量减少,在资源有限的应用中
    发表于 01-05 13:52

    使用<cont.h>进行协作多任务处理?

    认为我可以使用来滚动自己的。文档有点稀疏...我想知道当由 cont_run() 生成的函数正常完成时(即不以 yield 退出)是否会发生这种情况,以及是否有检测函数是否正常退出或通过 yield 退出的方法?还有其他人玩过吗?关于协作
    发表于 02-23 06:57

    求助,有没有人能够实现协作多任务处理?

    有没有人能够实现协作多任务处理?除了破解 cont_run 和 cont_init 之外,我尝试过的任何事情似乎都奏效了。我想要像https://github.com/mikaelp
    发表于 02-24 06:35

    setjmp 构建简单协作多任务系统

    讨论一个利用标准C 语言setjmp 库函数实现查询协作多任务系统,给出完整的内核和样例程序
    发表于 05-15 13:32 10次下载

    C语言标准库实现抢占式多任务资料

    C语言标准库实现抢占式多任务,使用C语言标准库实现,可以方便的移植到51单片机上,总的代码量243行,占用空间少,对于资源有限单片机也适用,
    发表于 12-31 18:00 4次下载

    用c语言实现查询红外解码

    #MCU 用c语言循环 红外解码红外解码的实现一般有定时器中断、外部中断+定时器、查询三种解码方法
    发表于 01-13 13:37 3次下载
    用c<b class='flag-5'>语言实现查询</b>红外解码