RT-Thread任务间同步及通信

在多实时任务操作系统中,一项工作的完成往往可以通过多个任务协调的方式共同来完成。例如,一个任务从传感器中接收数据并且将数据写到共享内存中,同时另一个任务周期性的从共享内存中读取数据并发送显示,如下图两个线程间的数据传递

如果对共享内存的访问不是排他性的,那么各个线程间可能同时访问它。这将引起数据一致性的问题,例如在显示线程显示数据之前,,传感器线程还未完成数据的写入,那么显示将包含不同时间采样的数据,造成显示数据的迷惑。

将传感器数据写入到共享内存的代码是接收线程的关键代码,将传感器数据从共享内存中读出的代码是显示线程的关键代码,这两段代码都会访问共享内存。正常的操作序列应该是在一个线程对共享内存块操作完成后,才允许另一个线程去操作。对于操作/访问同一块区域,称之为临界区。任务的同步方式有很多种,其核心思想都是:在访问临界区的时候只允许一个(或一类) 任务运行。

关闭中断

关闭中断也叫中断锁,是禁止多任务访问临界区最简单的一种方式,即使是在分时操作系统中也是如此。当中断关闭的时候,就意味着当前任务不会被其他事件打断(因为整个系统已经不再响应那些可以触发线程重新调度的外部事件),也就是当前线程不会被抢占,除非这个任务主动放弃了处理器控制权。关闭中断/恢复中断API接口由BSP实现,根据平台的不同其实现方式也大不相同。

关闭、打开中断接口由这两个函数完成:

  • 关闭中断

rt_base_t  rt_hw_interrupt_disable(void)

这个函数用于关闭中断并返回关闭中断前的中断状态。

  • 恢复中断

void rt_hw_interrupt_enbale(rt_base_t level);

这个函数“使能”中断,它采用恢复调用rt_hw_interrupt_disable()函数前的中断状态,进行“使能”中断状态,如果调用rt_hw_interrupt_disable()函数前是关闭中断状态,那么调用此函数后依然是关闭中断状态。level参数是上一次调用rt_hw_interrupt_disable()时的返回值。

注意:由于关闭中断会导致整个系统不能响应外部中断,所以在使用关闭中断作为互斥访问临界区的手段时,首先必须要保证关闭中断的时间非常短,例如数条机器指令。

使用场合

使用中断锁来操作系统的方法可以应用于任何场合,且其他几类同步方式都是依赖于中断锁而实现的,可以说中断锁是最强大和最高效的同步方法(简单粗暴)。只是使用中断锁最主要的问题在于,在中断关闭期间系统将不再相应任何中断,也就不能响应外部的事件。所以中断锁对系统的实时性影响非常巨大,当使用不当时会导致系统完全无实时性可言(可能导致系统完全偏离要求的时间需求);而使用得当,则会变成一种快速、高效的同步方式。

例如为了保证一行代码(例如赋值)的互斥运行,最快速的方法是使用中断锁而不是使用信号量或互斥量。

/*关闭中断*/
level = rt_hw_interrupt_disable();
a = a + value;

/*恢复中断*/
rt_hw_interrupt_enable(level);

在使用中断锁时,需要确保关闭中断的时间非常短,例如上面的代码中的a=a+value;也可换成另外一种方式,例如使用信号量:

/*获得信号量锁*/
rt_sem_take(sem_lock,RT_WAITING_FOREVER);
a = a+value;
/*释放信号量锁*/
rt_sem_release(sem_lock);

这段代码在rt_sem_take、rt_sem_release的实现中,已经存在使用中断锁保护信号量内部变量的行为,所以对于简单如a=a+value的操作,使用中断锁将变得更为简洁。

调度器锁

同中断锁一样把调度器锁住也能让当前运行的任务不被换出,直到调度器解锁。但和中断锁有一点不相同的是,对调度器上锁,系统依然能相应外部中断,中断服务例程依然能够进行相应的响应。所以在使用调度器上锁的方式进行任务同步时,需要考虑好任务访问的临界资源是否会被中断服务例程所修改,如果可能会被修改,那么将不适合采用这种方式进行同步。RT-Thread提供的调度锁操作API为:

void rt_enter_critical(void)                /*进入临界区*/

调用这个函数之后,调度器将被上锁,在锁住调度器期间,系统依然能够响应中断,如果中断唤醒了更高优先级的线程,调度器并不会立刻执行它,直到调用解锁调度器函数时才会尝试进行下一次的调度。

void rt_exit_critical(void)  /*退出临界区*/

当系统退出临界区的时候,系统将会计算当前是否拥有更高优先级的线程就绪,如果有比当前线程更高优先级的线程就绪时,将切换到这个高优先级线程中执行。如果无更高优先级的线程就绪,将继续执行当前任务。

注意:rt_enter_critical/rt_exit_critical可以多次嵌套调用,但每调用一次rt_enter_critical就必须相对应地调用一次rt_exit_critical退出操作,嵌套的最大深度为65535.

使用场合

调度器锁能够方便地使用于一些线程与线程间同步的场合,由于轻型,它不会对系统中断响应造成负担;但它的缺陷也很明显,就是它不能被用于中断与线程间的同步或通知,并且如果执行调度器锁的时间过长,会对系统的实时性造成影响(因为使用了调度器锁后,系统将不再具备优先级的关系,直到它脱离了调度锁的状态)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值