简易多任务抢占式调度器设计(一)
经典丶
|
2019.12.31
|
25104
+关注

“工程师在选用多任务操作系统前要先看看自已的项目是不是真需要用操作系统!如果你的任务可折分性较差,,折分后的各个任务之间有有N多的同步问题和复用资源问题,那么算了,我觉得你还是不要用多任务操作系统,或者将这些功能都放在一个任务里面,不要有事没事就觉得多任务好!多任务是用降低实时性来换取软件开发的独立性,不要被实时多任务操作系统的实时两个字骗了,这个实时只是相对于其它非实时性多任务操作系统来讲的,实时性最高的当然是你自已编写的单任务程序。

先直观地看一下多任务系统中的代码与单任务程序(前后台系统)的区别

1. Main.c
2. int Main(void)
3. {
4. TargetInit(); // 初 目标板
5. OSInit(); // 初 化操作系统
6. OSTaskCreate(Task0,&StackTask0[StackSizeTask0 - 1],PrioTask0); // 创 一个任务
7. Uart_Printf("Ready to start OS\n");
8. OSStart(); // 运行 操作系统
9. return 0; // 程 会运行至此
10. }
11. void Task0(void)
12. {
13. TargetStart(); // 设置中断向 量, 启动 操作系统的 硬件 时器 中断
14. Uart_Printf("Start OS\n");
15. // 创 其他 任务
16. OSTaskCreate(Task1,&StackTask1[StackSizeTask1 - 1],PrioTask1);
17. OSTaskCreate(Task2,&StackTask2[StackSizeTask2 - 1],PrioTask2);
18. OSTaskCreate(Task3,&StackTask3[StackSizeTask2 - 1],PrioTask3);
19. while(1)
20. {
21. Uart_Printf("Task0\n");
22. OSTimeDly(100); //1 秒运行
23. }
24. }
25. void Task1(void)
26. {
27. while(1)
28. {
29. Uart_Printf("Task1\n");
30. OSTimeDly(300); //3 秒运行
31. }
32. }
33.
34. void Task2(void)
35. {
36. while(1)
37. {
38. Uart_Printf("Task2\n");
39. OSTaskSuspend(PrioTask2); // 使自己进 入挂起 状态
40. }
41. }
42. void Task3(void)
43. {
44. while(1)
45. {
46. Uart_Printf("Resume Task2\n");
47. OSTaskResume(PrioTask2); // 恢复任务 2
48. OSTimeDly(800);
49. }
50. }

程序中创建了四务个任务,任务0每每1秒运行一次务,任务1每每3秒运行一次务,任务2运行一次即把自己挂起,任务3每每8秒运行一次并把任务2恢复。

在终端的运行结果如下图:

一、什么是多任务系统?

就像我们用电脑时可以同时听歌,上网,编辑文档等。在多任务系统中,可以同时执行多个并行任务,各个任务之间互相独立。通过操作系统执行任务调度而实现宏观上的”“并发运行”。从宏观上不同的任务并发运行,好像每个任务都有自己的的CPU一样。

其实在单一CPU的情况下,是不存在真正的多任务机制的,存在的只有不同的任务轮流使用用CPU,,所以本质上还是单任务的。但由于于CPU执行速度非常快,加上任务切换十分频繁并且切换的很快,所以我们感觉好像有很多任务同时在运行一样。这就是所谓的多任务机制。

多任务的最大好处是充分利用硬件资源,如在单任务时(大循环结构,如大分部分51程序)遇到到delay函数时,CPU在空转;而在多任务系统,遇到到delay或需等待资源时系统会自动运行下一个任务,等条件满足再回来运行先前的任务,这样就充分利用了CPU,提高了效率。

任务有下面的特性:

l 动态性。任务并不是随时都可以运行的,而一个已经运行的任务并不能保证一直占有CPU直到运行完。一般有就绪态,运行态,挂起态等。

下面我们来分析代码是如何实现状态转换的。

1. RTOS.h
2. INT32U OSRdyTbl; /* 就 任务 表 */

上面定义个一个32位变量,每一位代表一个任务,0表示挂起状态,1表示就绪状态。它记录了各任务的就绪与否状态,称它为就绪表。OSRdyTbl定义为为32位变量,对应32个任务。当然,定义为为64位的话,便最多能支持64个任务。

这样,可以定义两个宏,实现把任务的状态变为就绪或挂起态

1. RTOS.h
2. /* 在就 绪表 登记 任务 */
3. #define OSSetPrioRdy(prio) \
4. { \
5. OSRdyTbl |= 0x01<<prio; \
6. }
7. /* 从 绪表 删除 任务 */
8. #define OSDelPrioRdy(prio) \
9. { \
10. OSRdyTbl &= ~(0x01<<prio); \
11. }
为了增加程序可移植性和直观性 ,代码中常使用重定义的数据类型。在def.h 中有
1. typedef unsigned char BOOLEAN;
2. typedef unsigned char INT8U; /* Unsigned 8 bit quantity */
3. typedef signed char INT8S; /* Signed 8 bit quantity*/
4. typedef unsigned int INT16U; /* Unsigned 16 bit quantity */
5. typedef signed int INT16S; /* Signed 16 bit quantity*/
6. typedef unsigned long INT32U; /* Unsigned 32 bit quantity */
7. typedef signed long INT32S; /* Signed 32 bit quantity */

l 独立性。任务之间互相独立,不存在互相调用的关系。所有任务在逻辑上都是平等的。由于任务之间互相看不见,所以他们之间的信息传输就无法当面完成。这就需要各种通信机制如信号量,消息邮箱,队列等来实现。

l 并发性。由同一个处理器轮换地运行多个程序。或者说是由多个程序轮班地占用处理器这个资源。且在占用这个资源期间,并不一定能够把程序运行完毕。

精选留言
延伸阅读
2020.10.02
2922阅读
更多报告干货
写留言
3765
阅读
收藏
回到顶部