信号量保护之禁止中断
让我们举个例子。记DeviceALocked是一个位于内存中的R/W变量,用于指示设备A是否已经在使用中。任何一个任务,若欲使用设备A,都必须先检查这个变量的值。如果它的值为零,则表示设备可以使用。在任务获取到设备A后,它要把DeviceALocked的值改为1,表示设备A已经被占用。在设备A使用完毕后,该任务通过重新清零DeviceALocked来释放设备A,从而使其它任务可以使用此设备。
看起来这是个如意算盘。不过可否想过,如果两个任务都想访问设备A,是否有潜在的危险?比如,在任务1读取了DeviceALocked后,发现是零于是准备使用此设备,但还没来得及把它改为1,就不巧被调度器切出(比如,轮转调度),然后调度器让任务2执行,于是任务2也读到零,从而它使用设备A。但是在任务2在用完设备A之前,调度器又切回任务1。由于任务1早先读回来的是零,所以它认为设备A是空闲的,于是使用设备A,这时就违背了设备A必须互斥访问的限制,使系统出现紊乱危象!如果设备A是台打印机,则把两个文档的内容打在了一起;如果设备A是油门控制器,则可能使汽车失控或熄火,后果不堪设想。
----------------------------------------------------------------摘自《权威指南》
使用信号量之前必须创建信号量,否则可能导致不可预料的后果,主要表现在如下:
在不开启参数检查的情况下,刚好通过了后面的判断语句而继续往下执行,必然会导致程序出错。因为你根本不知道地址为0的位置的数据到底是什么,很可能刚好就等于OS_EVENT_TYPE_SEM而继续执行。所以在调试阶段,建议打开参数检查功能,当程序完成之后再关闭该功能。
信号量挂起(OSSemPend)有两个限制:
不可以在中断使用;
不可以在关闭调度的情况下使用。
在执行OSSemPost时,一旦发现有任务在等待该信号量,就会从最等待该信号量的所有任务中寻找最高优先级的任务进入就绪态,并将该任务从等待该信号量的事件表移除。但是要注意进入就绪态后不一定马上能运行。还有一点,如果没有任务在等待该信号量,那么这个信号量计数器是会自加的,直到最大值。
关中断
最简单的方法就是采用关中断的方式进行数据的保护。但是这样会增加中断响应时间。
在什么情况下需要关闭中断呢?
1、操作的对象是共享资源(全局变量),其他任务可能在整个操作流程中打断你的操作,并且会更改你的全局变量,最终会引起非常严重的后果的情况下需要关中断。
2、当任务在执行对时序要求非常高的操作,因为被其它任务中断浪费了很多时间,当回来的时候错过了dead time,最终导致操作失败。
---------------------------------------------------------------------------------------2018/08/23Osprey
有的时候考虑一些中断在操作系统运行的时候还能继续工作,这个时候就需要使用中断屏蔽寄存器了。 链接如下:
https://www.amobbs.com/thread-5547895-1-1.html