嵌入式系统作业
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
嵌入式系统作业
互斥(Mutual Exclusion)互斥是用来控制多任务对共享数据进行串行访问的同步机制。在多任务应用中,当两个或多个任务同时访问共享数据时,可能会造成数据破坏。互斥使它们能串行地访问数据,从而达到保护数据的目的。实现资源互斥访问的方法很多,不同之处仅在于互斥的范围和程度,互斥的本质是为了有序地利用资源,与共享资源打交道时,使之满足互斥条件最一般的方法有:关中断、使用测试并置位指令、禁止做任务切换、利用信号量。
1关中断
优点:访问共享资源最简单的方法是关中断: 一个任务在对共享资源进行访问前将中断关闭, 然后执行访问共享资源的关键段落代码, 访问共享资源结束后再打开中断。如果在参入访问共享资源的并发程序单元中包括ISR(中断服务程序)时, 任务级程序单元只能用关中断的措施来访问共享资源。中断被关闭后, 系统失去了对所有事件的反映能力, 不可能进行任务的切换, 从而保证了共享资源的独占式访问。
缺点:由于关中断延迟了对中断的响应时间, 直接影响了系统的实时性, 因此一般用于对简单共享资源的短暂访问。因此在上锁期间,它可能造成系统对外部事件反应迟钝。这对于大多数实时系统而言,系统的实时性也就得不到保证,因而不适合作为一种通用的互斥方法。然而当涉及到任务和中断服务程序共享数据时,中断上锁又是唯一的方法。但是在任何情况下,应该使中断上锁时间尽量短,这也是所有实时系统的基本要求。
关中断方法实现互斥程序:
void Function (void){
关中断;
处理共享资源;
开中断;
}
开中断程序:
Disable interrupts; /*关中断*/ Access the resource (read/write from/to variables); /*读/写变量*/ Reenable interrupts; /*重新允许中断*/ μC/OS-Ⅱ在处理内部变量和数据结构时就是使用的这种方法,即使不是全部,也是绝大部分。它提供了关中断(OS_ENTER_ CRITICAL())和开中断(OS_EXIT_CRITICAL())两个宏调用,以方便用户利用C代码开关中断。
利用μC/OS-Ⅱ宏调用关中断和开中断的程序:
void Function(void){
OS_ENTER_CRITICAL();//宏调用,关中断
处理共享数据;
OS_EXIT_CRITICAL();//宏调用,开中断
}
关中断这种互斥方法是在中断服务子程序中处理共享变量或共享数据结构的唯一手段,当改变或者复制某些变量、结构的值时,这也是一个好方法。
2 使用测试并置位指令
测试并置位:Test and Set,TAS,当两个任务共享一个资源时,设置一个全局标志变量并约定在访问共享资源以前先测试标志变量是否为1:
①:若为1则表明共享资源正在被其它任务所访问,该任务继续等待直到标志变量为0。
②:若标志变量为0,则任务将标志变量置位,然后访问共享资源,访问完毕后再清标志变量。
③:若置位和清零标志变量只需一条不会被中断的语句,不需要用开关中断的方法来保护对标志变量的操作,否则在操作前后还要使用禁止与允许中断,以免标志变量被破坏。
TAS方法流程图:
程序清单如下:
Disable interrupts;关中断
if (‘Access Variable’ is 0) 如果资源不可用,标志为0
{
Set variable to 1; 置资源不可用,标志为1
Reenable interrupts; 重开中断
Access the resource; 处理该资源
Disable interrupts; 关中断
Set the ‘Access Variable’ back to 0;
Reenable interrupts;
}
else
{
Reenable interrupts;
}
3禁止做任务切换
禁止做任务切换的基本原理是:任务切换也称为CPU寄存器内容切换,当多任务内核要运行其他任务时,它将正在运行任务的当前状态(CPU寄存器中的所有内容)保存在自己的堆栈中。入栈完成后,将下一个将要运行的任务的当前状况从该任务的栈中重新装入CPU的寄存器,并开始下一个任务的运行。如果任务不与中断服务子程序共享变量或数据结构,可以使用禁止,然后允许任务切换。可以采用给任务切换上锁,然后开锁的方法实现数据共享。若任务不与中断服务子程序共享变量或数据结构,可使用此方法,此时,中断任然是开着的,应尽量避免使用此方法,它与内核对任务的调度功能相违背。用给任务切换上锁,然后开锁的方法实现数据共享:
利用禁止调度方法实现互斥的程序:
void Function (void)
{
OSSchedLock();//内核函数,调度上锁
处理共享数据(中断是开放的);
OSSchedUnlock(); //内核函数,调度解锁
}
4利用信号量
利用信号量的基本原理是:信号量实际上是一种约定机制,用于:控制共享资源的使用权(满足互斥条件);标志某个事件的发生;使两个任务同步。信号量是计数式的,其值取决于所用的内核。一般,对信号量实时三种操作:初始化(INITIALIZE),或称为建立(CREATE);等信号(WAIT),或称为挂起(PEND);
给信号(SINGAL)或发信号(POST);信号量初始化时要给信号量赋初值,等待信号量的任务表应清为空想要的到信号量的任务执行等待(WAIT)操作。任务以发信号操作(SIGNAL)释放信号量。μC/OS-II只支持优先级法,也就是等待信号量任务中优先级最高的。使用信号量之前,一定要对该信号量做初始化,作为互斥条件,信号量初始化为1。信号量是60年代中期Edgser Dijkstra 发明的。信号像是一把钥匙,任务要运行下去,得先拿到这把钥匙。如果信号已被别的任务占用,该任务只得被挂起,直到信号被当前使用者释放。换句话说,申请信号的任务是在说:“把钥匙给我,如果谁正在用着,我只好等!”信号是只有两个值的变量,信号量是计数式的。只取两个值的信号是只有两个值0和1的量,因此也称之为信号量。计数式信号量的值可以是0到255或0到65535,或0到4294967295,取决于信号量规约机制使用的是8位、16位还是32位。到底是几位,实际上是取决于用的哪种内核。根据信号量的值,内核跟踪那些等待信号量的任务。
以下程序清单示意在μC/OS-II中如何用信号量处理共享数据。要与同一共享数据打交道的任务调用等待信号量函数OSSemPend()。处理完共享数据以后再调用释放信号量函数OSSemPost()。这两个函数将在以后的章节中描述。要注意的是,在使用信号量之前,一定要对该信号量做初始化。作为互斥条件,信号量初始化为1。使用信号量处理共享数据不增加中断延迟时间,如果中断服务程序或当前任务激活了一个高优先级的任务,高优先级的任务立即开始执行。
程序清单通过获得信号量处理共享数据:
OS_EVENT *SharedDataSem;
void Function (void)
{
INT8U err;
OSSemPend(SharedDataSem,0,&err);
OSSemPost(SharedDataSem);
}
利用信号量访问共享资源示例:
①假设允许两个任务同时向共享串口发送数据,任务A要输出1、2、3,任务B要输出4、5、6,若不满足互斥条件,串口会交叉输出两个任务的数据,可能的结果是“1、4、2、5、3、6”。
②使用二值信号量并给信号量赋初值1,要想访问串口的任务,首先请求信号量,得到该资源的访问权。谁先得到,谁先使用。