本章是概述性的内容。可以把多任务系统当做一个团队,里面的每一个任务就相当于团队里的一个人。团队成员之间要协调工作进度(同步)、争用会议室(互斥)、沟通(通信)。多任务系统中所涉及的概念,都可以在现实生活中找到例子。
各类RTOS都会涉及这些概念:任务通知(task notification)、队列(queue)、事件组(event group)、信号量(semaphoe)、互斥量(mutex)等。我们先站在更高角度来讲解这些概念。
10.1 同步与互斥的概念
一句话理解同步与互斥:我等你用完厕所,我再用厕所。
什么叫同步?就是:哎哎哎,我正在用厕所,你等会。 什么叫互斥?就是:哎哎哎,我正在用厕所,你不能进来。
同步与互斥经常放在一起讲,是因为它们之的关系很大,“互斥”操作可以使用“同步”来实现。我“等”你用完厕所,我再用厕所。这不就是用“同步”来实现“互斥”吗?
再举一个例子。在团队活动里,同事A先写完报表,经理B才能拿去向领导汇报。经理B必须等同事A完成报表,AB之间有依赖,B必须放慢脚步,被称为同步。在团队活动中,同事A已经使用会议室了,经理B也想使用,即使经理B是领导,他也得等着,这就叫互斥。经理B跟同事A说:你用完会议室就提醒我。这就是使用"同步"来实现"互斥"。
有时候看代码更容易理解,伪代码如下:
假设有A、B两人早起抢厕所,A先行一步占用了;B慢了一步,于是就眯一会;当A用完后叫醒B,B也就愉快地上厕所了。
在这个过程中,A、B是互斥地访问“厕所”,“厕所”被称之为临界资源。我们使用了“休眠-唤醒”的同步机制实现了“临界资源”的“互斥访问”。
同一时间只能有一个人使用的资源,被称为临界资源。比如任务A、B都要使用串口来打印,串口就是临界资源。如果A、B同时使用串口,那么打印出来的信息就是A、B混杂,无法分辨。所以使用串口时,应该是这样:A用完,B再用;B用完,A再用。
10.2 同步与互斥并不简单
在裸机程序里,可以使用一个全局变量或静态变量实现互斥操作,比如要互斥地使用LCD,可以使用如下代码:
但是在RTOS里,使用上述代码实现互斥操作时,大概率是没问题的,但是无法确保万无一失。
假设如下场景:有两个任务A、B都想调用LCD_PrintString,任务A执行到第4行代码时发现bCanUse为1,可以进入if语句块,它还没执行第6句指令就被切换出去了;然后任务B也调用LCD_PrintString,任务B执行到第4行代码时也发现bCanUse为1,也可以进入if语句块使用LCD。在这种情况下,使用静态变量并不能实现互斥操作。
上述例子中,是因为第4、第6两条指令被打断了,那么如下改进:在函数入口处先然让bCanUse减一。这能否实现万无一失的互斥操作呢?
把第4行的代码使用汇编指令表示如下:
假设如下场景:有两个任务A、B都想调用LCD_PrintString,任务A执行到第04.1行代码时读到的bCanUse为1,存入寄存器R0就被切换出去了;然后任务B也调用LCD_PrintString,任务B执行到第4行时发现bCanUse为1并把它减为0,执行到第5行代码时发现条件成立可以进入if语句块使用LCD,然后任务B也被切换出去了;现在任务A继续运行第04.2行代码时R0为1,运行到第04.3行代码时把bCanUse设置为0,后续也能成功进入if的语句块。在这种情况下,任务A、B都能使用LCD。
上述方法不能保证万无一失的原因在于:在判断过程中,被打断了。如果能保证这个过程不被打断,就可以了:通过关闭中断来实现。
示例1的代码改进如下:在第5~7行前关闭中断。
示例2的代码改进如下:在第5行前关闭中断。
10.3 各类方法的对比
能实现同步、互斥的内核方法有:任务通知(task notification)、队列(queue)、事件组(event group)、信号量(semaphoe)、互斥量(mutex)。
它们都有类似的操作方法:获取/释放、阻塞/唤醒、超时。比如:
这些内核对象五花八门,记不住怎么办?我也记不住,通过对比的方法来区分它们。
使用图形对比如下:
到此这篇内同步和外同步的区别(内和外同步的作用)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/bcyy/15594.html