实现多任务之间通信的最简便的办法是使用共享的数据结构。虽然共享数据区简化了任务间的通信,但是必须保证 每个任务在处理共享数据时的排他性。以避免竞争和数据破坏。共享资源满足互斥性的一般方法有:
1.关中断,开中断
2.使用测试并置位指令
3.禁止做任务切换
4.利用信号量
一.关中断&开中断
这估计是最简单的方法了,代码如下所示。
- void function(void)
- {
- OS_ENTER_CRITICAL(); //uCOS II中的宏调用,关中断
- /*处理共享数据*/ //读写变量
- OS_EXIT_CRITICAL(); //uCOS II中的宏调用,开中断
- }
注意:关中断的时间不能太长,因为它将影响整个系统的中断响应时间(中断延迟时间)。如果仅仅是做为几个变量赋值或者复制几个变量,可以考虑使用这种方法。一般来说:关中断的最长时间不能超过系统本身的关中断时间。
二:测试并置位操作
即放一个类似于标志位的变量,如果该变量为0,则允许和共享资源交互,而为1则不允许。为防止另一任务也要使用该资源,只需把改标志位置1.注意:这里的标志一般是一条不会被处理器中断的指令。否则应在程序中关中断对该标志位操作,然后再开中断。
这种指令被称作TAS(test and set)指令,在某些处理器中有硬件TAS指令。
三:禁止,然后允许任务切换
给任务上锁然后开锁 (具体见其它文)
例:
- void function(void)
- {
- OSSchedlock(); //给任务上锁
- /*在这里处理共享数据(中断是开着的)*/
- OSSchedUnlock();//给任务解锁
- }
四:信号量
信号量的本质是一种约定机制。其用于:
1.控制共享资源的使用权
2.标志某事件的发生
3.使两个任务的行为同步
信号量是任务得以运行的“钥匙”,要运行,必须先拿到“钥匙”。如果信号量被别的任务占用,则该任务挂起,直到信号量被当前的使用者释放。对信号量的操作有三种,初始化(inittialize)或者 建立 (creat);等待信号 (wait)或者挂起 (pend);给信号(signal)或者发信号(post)。信号量初始化时要给信号量赋初值,等待信号的任务列表应清空。
任务要得到信号量必须:等待(wait),如果信号量有效(大于0),信号量-1任务得以运行。如果信号量为0,任务列入等待信号量任务列表,多数内核支持定义超时。如果等待时间超过了某一个值,该信号量是还无效的,则等待信号量的任务进入就绪状态。准备运行,并返回错误代码(指出发生超时错误)。
任务以发信号的方式释放信号量,如果没有任务等待信号量。信号量只是简单的加1.如果有任务等待该信号量,信号量的值就不加1.于是“钥匙”给了等待信号量的任务中的一个。至于任务的选择要看内核是如何调度的:
1.等待信号量的任务中优先级最高的
2.最早等待信号量的任务(FIFO)uCOS II只支持优先级法。
例:
- OS_EVENT *ShareDataSem;
- void function(void)
- {
- INT8U err;
- OSSemPend(SharedDataSem,0,&err);
- /*处理共享数据(中断是开着的)*/
- OSSemPost(ShareDataSem);
- }
当多个任务共享输入输出设备时,信号量很有用。
但要注意:信号量不能用过头,处理很简单的数据共享都用信号量,信号量的创建和释放都是要花很多时间的。这种额外的负荷是不必要的。