技术交流QQ群【JAVA,C++,Python,.NET,BigData,AI】:170933152
来看一个使用信号量,进行任务同步的案例
这里先说明一下,这个
比如这里有个A任务,有个B任务
那么在A任务重,按下key1,这个时候,B任务就要显示LED1亮,
所以这里的同步就是,只要key1进行了操作,B任务中对应的LED1就要
跟随做出对应的动作.
这里只是说了一个简单的例子,实际上,网络数据处理,可以用这个信号量来完成,
比如中断接收到数据,就要求,任务要立即处理这个网络数据,那么,要保证这个同步,
这里就要用到这个信号量了.
可以看看这里有三个任务
START任务,TASK1任务,TASK2任务
这个是这个start任务
这里面创建了一个信号量,这里可以看到这个信号量设为0了,也就是
没办法被使用的,只有一个任务上来,先post释放一下这个信号量,然后才能使用.
否则的话,就永远请求不到信号量了.
然后再去看看TASK1,TASK2
先看看任务1,这里可以看到按下WKUP按键的时候
先去发送信号量,也就是先去释放信号量,也就说,
释放信号量就是给信号量的值去+1,请求信号量就是这个信号量的值就-1
-1减到0的时候,就请求不到信号量了.
可以看到这里SYNC_SEM.Ctr,这里要显示这个SYNC_SEM.Ctr这个值,这个值就是
当前信号量的值,可以打印到屏幕上通过LCD
可以看到这里任务1 ,上来先去释放信号量也就是+1,给信号量
然后再去看看任务2
可以看到这个任务2中,先去请求信号量,信号量-1,然后去显示这个信号量
然后填充区域
然后再发生任务调度.
然后下载到开发版看看:
下载进去以后什么都没有操作,默认的界面是上面的
如果,信号量改变的时候,会刷新上面的区域,并且显示信号量的值.
如果这个时候,我们去按下WKUP按键,来发送信号量,也就是给信号量+
那么可以看到,信号量+以后,task2就可以请求到信号量了,这个时候
task2就可以刷新屏幕了
但是,一旦信号量位0了task2,就没办法请求到信号量,这个时候屏幕就不刷新了,
如果咱们多次按下WKUP按键的话,那么信号量会+1,不停的+1
这样的话,停止按WKUP的时候,可以看到,
task2,会一边消耗信号量,一边刷屏,直到信号量是0的时候
屏幕又不刷新了.
这个案例,就是信号量同步的一个案例,然后
再去看看,优先级反转的概念.
接下来看一下这个,来理解一下什么是优先级反转,首先要明确优先级反转是我们应该
尽量避免的.
比如这里有任务H,任务M,任务L
优先级分别是任务H,>任务M,>任务L
这里从任务L开始,比如任务L正在请求信号量,先去执行,执行到任务L获得信号量的时候,他去执行,
可以看到绿色的3这里是任务L进行执行的过程,然后,如果这个时候
任务L执行到一半发生了任务切换,这个时候因为任务H的优先级比较高,所以,任务H就去执行了,但执行的时候
任务H去申请信号量,结果这个时候,信号量因为被任务L占用,所以这个时候,任务H就被挂起了,
然后继续执行任务L去了,这个地方是7,然后,任务L执行着的时候,这个时候任务M这个时候,挂起完毕了,
这个时候因为任务M的优先级比较高,然后就去执行任务M,这个时候任务M去申请信号量,这个时候
因为信号量,还是被任务L占用,还是没有被释放,所以任务M申请信号量的时候,还是没有申请到.
那么任务M还是被迫要挂起,把CPU使用权让出来给任务L用,那么任务L继续执行,执行到11,这个地方
这个时候任务L终于使用完信号量了,这个时候任务L再去释放信号量,然后发生任务切换,这个时候
才,任务H去申请信号量,才申请到信号量,这时候,任务H获得信号量,继续去执行.
这样的话,就出现了,上面画出的,这部分,发生了优先级反转.本来任务H的优先级高,应该是任务H去执行的,
但是任务H却没能执行,而是任务L去执行了.也就是优先级低的却执行了,类似于发生了优先级反转.
这里为了解决这个问题,那么在UCOSIII中,提供了这样的方法就是,当任务L在执行的时候,占时把
任务L的优先级提升到和任务H的优先级一样,这个时候就不会出现优先级反转的现象了.
这个就是互斥信号量的概念.
可以看到这里,任务L执行到3这个位置的时候,获得互斥信号量,然后执行,这个时候发生了
任务切换,那么任务H的优先级比较高,所以先去执行任务H,那么这个时候,任务H就去请求互斥信号量,这个时候
因为互斥信号量被任务L正在占用,所以,任务H只能放弃使用,这个时候UCOSIII会做一个动作就是
把任务L的优先级占时提升到和任务H一样,然后任务L继续,使用信号量,继续执行,执行以后,直到释放信号量,然后
它再把自己的信号量释放掉.同时UCOSIII,再把任务L的优先级,降为原来的优先级.
可以看到这样有个好处就是,当任务L发生任务切换的时候,本来应该给任务H执行的,因为任务H的优先级高
但是由于任务H获取不到信号量,所以继续任务L执行,任务L执行到一半又发生任务切换,这个时候因为
任务L的优先级已经被系统提升到和任务H的优先级一样了,所以这个时候,虽然任务H在挂起中,任务M
已经可以运行了,但是任务M也不会剥夺CPU的使用权.这样就避免了剥夺CPU使用权造成的资源浪费的问题.
去看看案例:
根据前面说的,互斥信号量的实验有3个任务
高中低
然后定义一个信号量
然后在主函数main函数中:
要创建信号量
这里这个信号量初始值为1
然后下面创建3个任务
然后去看high_task 高优先级的任务
可以看到高优先级任务中,首先通过延时,产生任务调度
然后串口打印
然后请求信号量
然后LCD填充,然后LED翻转,然后
释放信号量
然后通过延时,产生任务调度
再去看看中优先级任务:
可以看到中等优先级任务,跟信号量没有关系
他没有使用信号量.
然后这里看看这个low_task这个低优先级任务
这里面先去请求信号量,请求以后,
然后这里有个循环,注意这个循环,用来不停的发起任务调度,这里发起任务调度以后
但是没有释放信号量,意味着,这个低优先级的任务,会被提升优先级,
最后,循环完了再,释放信号量,然后再延时,触发任务调度.
所以这里只有,高优先级和低优先级用到了信号量
下载到开发版,分析一下
可以看到第一个是middle task running
为什么高优先级任务没有第一个执行呢?
因为高优先级任务,中延时了500ms对吧,然后触发任务调度了.
middle task running 打印以后
下面是low task running
低优先级任务执行了,因为高优先级任务还没有延时结束所以这里
低优先级任务就先执行了.
低优先级一边执行着,一边去触发任务调度,这个时候
高优先级延时完成了以后,可以看到,就去发送信号量请求了
high task pend sem
然后这个时候,虽然高优先级任务去请求信号量,但是低优先级任务,还在占用信号量,
所以这个是cpu使用权就交给了中优先级任务
middle task running,可以看到打印出了这句话.
这里一直打印middle task running
感觉就像高优先级任务被降低了
这里就是可以认为发生了优先级反转的过程.
然后可以看到high task running,这个时候低优先级任务终于执行完了,然后
让出了信号量,可以看到high task running,高优先级终于可以继续获得信号量执行了
然后下面又是这样的循环.
这就是这个优先级反转的例子.
然后再看一个
互斥信号量的例子:
这个实验和上面那个实验的代码几乎是一样的.
只是把使用信号量的地方,换成了互斥信号量
比如这里定义了互斥信号量,
咱们回去再现看一下互斥信号量的函数.
去看看代码
OSMutexGreate创建互斥信号量
这类p_mutex是互斥信号量
然后p_name是互斥信号量名字
p_err是错误码
然后
OSMutexDel()删除互斥信号量
第一个是互斥信号量,参数
第二个是选项,
第三个是错误码
然后再去看看: 这个选项
第一个
OS_OPT_DEL_NO_PEND 等待没有互斥信号量请求的时候,再删除
OS_OPT_DEL_ALWAYS 是不管有没有互斥信号量的请求,都会删除.