UC/OS三种临界区管理机制

目录

1、临界段与临界资源

1.1、临界段

1.2、临界资源

2、三种临界区管理机制

2.1、示例代码

2.2、PSW(程序状态字)

2.3、方法一

2.4、方法二

2.5、方法三

3、获取UCOS源码


1、临界段与临界资源

操作系统中有两个名词,临界段和临界资源。

1.1、临界段

代码的临界段也称为临界区,指处理时不可分割的代码。一旦这部分代码开始执行,则不允许任何中断打入。为确保临界段代码的执行,在进入临界段之前要关中断,而临界段代码执行完以后要立即开中断。

1.2、临界资源

临界资源在一段时间内只允许一个进程访问的资源。又称独占资源。资源可以是输入输出设备,例如打印机、键盘、显示器,资源也可以是一个变量,一个结构或一个数组等。

2、三种临界区管理机制

2.1、示例代码

在µC/OS-II中有三种临界区管理方式,是在oc_cpu.h文件中通过宏OS_CRITICAL_METHOD来控制,如下图为8086临界区实现方式

2.2、PSW(程序状态字)

不管是何种芯片,进入临界区的思想是不变的,就是失能控制PSW(Program Status Word)中的IF(中断标志位)标志位。8086的标志寄存器如下图所示。不同芯片的PSW略微不同。

2.3、方法一

方法1是直接将OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()定义为处理器的关闭(CLI)和打开(STI)中断指令。STI(Set Interrupt) 为开中断,CLI(Clear Interrupt) 为关中断,这里设置的是PSW(Program Status Word)中的中断标志位。

但这种方法有一个隐患,如果在关闭中断后调用µC/OS函数,当函数返回后,中断将被打开!严格意义上的关闭中断应该是执行OS_ENTER_CRITICAL()后中断始终是关闭的, 方法1显然不满足要求。但方法1的优点是简单,执行速度快(只有一条指令)。

2.4、方法二

OS_ENTER_CRITICAL()会在关中断前保存之前的标志寄存器内容到堆栈中,随之将中断关闭,OS_EXIT_CRITICAL()从堆栈中恢复之前保存的状态。

PUSHF是将标志寄存器入栈,POPF是将栈顶的内容弹出到标志寄存器中。

但是一些编译器不能很好地优化内联代码,因此,此方法可能无法正常工作。因为编译器可能不够智能,无法知道堆栈指针已经被更改(通过PUSHF指令),此时再想去访问堆栈中的数据极大可能出现错误的值,从而导致应用程序的崩溃。

2.5、方法三

一些编译器提供了扩展的接口允许用户获取PSW中的值,并将此状态值保存在声明的变量中,随之将中断关闭,在退出临界区时,在将上面保存的值恢复到PSW中。

OSCPUSaveSR以及OSCPURestoreSR是在os_cpu_a.s文件中定义的,使用汇编指令实现的。

这种方法的优点就是安全可靠,缺点就是执行速度较上面两种慢,因为进入和退出临界区的汇编代码可能不止一条,而且还需要访问内存变量cpu_sr。

3、获取UCOS源码

可以在官网中获取一些单片机型号的示例代码,如下链接。
https://weston-embedded.com/micrium-examples

进入页面后,可以在页面下方找常用单片机型号的示例程序,但是需要注册登陆之后才可以下载,使用QQ邮箱注册官网还不认为是一个有效的邮箱。在此我已经下载了STM32103/107的示例代码了,有需要的可以关注“typedef”微信公众号在后台回复“TD600006”可获得百度云链接。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是uC/OSIII互斥信号量实验代码和解释: ```C #include <includes.h> #define TASK_STK_SIZE 128 #define TASK_PRIO_0 0 #define TASK_PRIO_1 1 OS_MUTEX mutex1; static OS_TCB Task0TCB; static CPU_STK Task0Stk[TASK_STK_SIZE]; static OS_TCB Task1TCB; static CPU_STK Task1Stk[TASK_STK_SIZE]; static void Task0(void *p_arg) { OS_ERR err; while (1) { OSMutexPend(&mutex1, 0, OS_OPT_PEND_BLOCKING, 0, &err); // 临界区代码 OSMutexPost(&mutex1, OS_OPT_POST_NONE, &err); } } static void Task1(void *p_arg) { OS_ERR err; while (1) { OSMutexPend(&mutex1, 0, OS_OPT_PEND_BLOCKING, 0, &err); // 临界区代码 OSMutexPost(&mutex1, OS_OPT_POST_NONE, &err); } } int main(void) { OS_ERR err; OSInit(&err); OSMutexCreate(&mutex1, "Mutex1", &err); OSTaskCreate(&Task0TCB, "Task0", Task0, 0, TASK_PRIO_0, &Task0Stk[0], TASK_STK_SIZE / 10, TASK_STK_SIZE, 0, 0, 0, &err); OSTaskCreate(&Task1TCB, "Task1", Task1, 0, TASK_PRIO_1, &Task1Stk[0], TASK_STK_SIZE / 10, TASK_STK_SIZE, 0, 0, 0, &err); OSStart(&err); return 0; } ``` 在这个实验中,我们创建了两个任务,它们共享一个临界资源。我们使用uC/OSIII提供的互斥信号量来保护这个临界资源,以确保两个任务不会同时访问它。 在任务函数中,我们首先调用OSMutexPend函数来获取互斥信号量。如果互斥信号量不可用,则任务会被挂起,直到它可用为止。一旦我们获得了互斥信号量,我们就可以访问共享资源了。在临界区代码执行完毕后,我们调用OSMutexPost函数来释放互斥信号量,以便其他任务可以使用。 在主函数中,我们首先初始化uC/OSIII内核,然后创建互斥信号量。接下来,我们创建两个任务,并将它们添加到uC/OSIII任务列表中。最后,我们调用OSStart函数来启动uC/OSIII内核,任务开始执行。 注意:以上代码仅供参考。您需要根据自己的需求进行修改和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值