1裸机与RTOS的理解
首先这里只针对单核CPU架构的芯片展开讨论,大部分是MCU吧,而多核CPU的讨论相对比较复杂,暂不涉及~
玩RTOS的朋友都知道,裸机与OS的最大区别就是实现多任务的并发,其实你说裸机就不能实现任务的并发吗 ? 这个需要看所站的角度吧,只是说RTOS并发的粒度可以更加细,因为把裸机的任务拆分成多块运行,其实也是一种并发方式。
从宏观上虽然RTOS的每个任务都是在并发执行,其实微观上还是一条一条指令在顺序执行着,如下图所示:
而对于目前主流的RTOS,如UCOS或者FreeRTOS,所实现的都是多任务,更多的是一种多线程的并发执行而非多进程,所以对应到Linux平台上称他们为thread。
2并发带来的问题
并发的好处就是能够在更细的粒度来尽可能的提高CPU的利用率,这里不能说使用了多线程就一定能提高,这与你所设计的任务划分和处理有着直接的关系,只能说
多线程相比裸机更有这个能力。
而任何事物都有其利弊,多个任务在没有同步处理的情况下,任务之间是无序运行的,无序也就意味着状态的多样性和复杂度。
当然bug菌这里所说的无序是一个相对的过程,比如对于CPU而言,它就是顺序的去执行一条一条的指令,所以在这个层面它是有序的、确定的。
而把过程放大,比如执行一条C语言语句,一般它是由多条汇编指令组成,对于目前的抢占式内核,在一段时间内其多个任务就有可能指令交替执行,当这些指令都去操作同一块内存,那么内存的最终结果由于顺序不同而不同,最终难以确定。
状态的不确定就有可能造成异常行为,也就是大家经常遇到的:"怎么跑着跑着就有问题,还没啥规律~","这段代码怎么看也没问题呀~"
所以对比看来RTOS确实会带来编程上的难度~
3临界区
既然有难度,我们就要解决,把不确定性部分通过一些手段来变得确定,而造成这些不确定因素的动力是什么呢?是中断~
bug菌一直觉得,其实对于裸机而言,如果把中断服务函数看成一个更高优先级的抢占式任务,其实裸机主任务与中断任务就形成了一种两任务的并发,所以中断与任务之间也是有共享问题需要类似处理的。
为了解决这些不确定因素,我们只需要在这段代码区域限制中断的发生即可,这一段区域就是临界区,说得直白点 : 关中断与开中断。
1ENTER_CRITICAL();//进入临界区 2 3//临界区代码 4 5EXIT_CRITICAL();//退出临界区
4临界区嵌套
临界区的使用没啥可说的,但是在你的代码中怎么加临界区确实一门技巧,可是说很多3~5年的工程师也并不一定处理得好,本文暂不展开,后面bug菌整理以后再分享给大家,今天只聊聊临界区嵌套使用的问题,毕竟很多朋友在这里掉过坑~
参考伪代码:
1/*********************************************
2 * Function: Fuction1
3 * Description:功能函数
4 * Author: bug菌
5/
6void Fuction1(void)
7{
8 ENTER_CRITICAL();//进入临界区
9
10 //do something~
11
12 EXIT_CRITICAL();//退出临界区
13}
14/*
15 * Function: Fuction2
16 * Description: 功能函数
17 * Author: bug菌
18 ********************************************/
19void Fuction2(void)
20{
21 ENTER_CRITICAL();//进入临界区
22
23 ......
24 Fuction1();
25
26 ......
27 //do something~
28
29 EXIT_CRITICAL();//退出临界区
30}
这种临界区的使用是很多朋友常犯的错误,当然这里的临界区操作仅仅只是开关中断,许多自己公司写的,或者裁剪的都是这种简约开关中断版本,所以当调用Function1函数以后,后面的代码就不在临界区内了,此时就有可能会存在共享问题。
当然目前的开源OS都会提供一种把相关嵌套标记保存在局部变量中的处理方式,如下代码所示:
1//来源于ucos源码
2#define OS_ENTER_CRITICAL() (cpu_sr = OSCPUSaveSR())
3#define OS_EXIT_CRITICAL() (OSCPURestoreSR(cpu_sr))
4
5/*********************************************
6 * Function: Fuction1
7 * Description:功能函数
8 * Author: bug菌
9 ********************************************/
10void Fuction1(void)
11{
12 int cpu_sr;
13
14 OS_ENTER_CRITICAL();//进入临界区
15
16 //do something~
17
18 OS_EXIT_CRITICAL();//退出临界区
19}
20
21/*********************************************
22 * Function: Fuction2
23 * Description: 功能函数
24 * Author: bug菌
25 ********************************************/
26void Fuction2(void)
27{
28 int cpu_sr;
29
30 OS_ENTER_CRITICAL();//进入临界区
31
32 Fuction1(void);
33
34 OS_EXIT_CRITICAL();//退出临界区
35
36}
为了更好的理解,我写了一下下面的伪代码,供大家参数~
1//中断寄存器register原本是1, 向register写0关中断,向register写1开中断
2
3void Fuction2(void)
4{
5 int cpu_sr1 = 0;
6
7 cpu_sr1 = register;
8 register = 0; //register == 0;cpu_sr1 == 1;
9
10 void Fuction1(void)
11 {
12 int cpu_sr1 = 0;
13
14 cpu_sr2 = register;
15 register = 0; //register == 0;cpu_sr2 == 0;
16
17
18 register = cpu_sr2;
19 cpu_sr2 = 0;//register == 0;cpu_sr2 == 0;
20 }
21
22 register = cpu_sr1;
23 cpu_sr1 = 0;//register == 1;cpu_sr1 == 0;
24
25}
不同的OS可能具体实现有所差异,大体上都一样~
来源:公众号,最后一个bug
审核编辑:汤梓红
-
芯片
+关注
关注
452文章
50134浏览量
420436 -
cpu
+关注
关注
68文章
10794浏览量
210697 -
RTOS
+关注
关注
21文章
809浏览量
119342 -
代码
+关注
关注
30文章
4710浏览量
68190
原文标题:RTOS中临界区的使用是门技术活~
文章出处:【微信号:嵌入式情报局,微信公众号:嵌入式情报局】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论