关闭中断
关闭中断也叫中断锁,是禁止多任务访问临界区最简单的一种方式,即使是在分时操作系统中也是如此。当中断关闭的时候,就意味着当前任务不会被其他事件打断(因为整个系统已经不再响应那些可以触发线程重新调度的外部事件),也就是当前线程不会被抢占,除非这个任务主动放弃了处理器控制权。关闭中断/恢复中断API接口由BSP实现,根据平台的不同其实现方式也大不相同。
关闭、打开中断接口由两个函数完成:
- 关闭中断
rt_base_t rt_hw_interrupt_disable(void);
这个函数用于关闭中断并返回关闭中断前的中断状态。
函数参数
无
函数返回
返回调用这个函数前的中断状态。
- 恢复中断
void rt_hw_interrupt_enable(rt_base_t level);
这个函数“使能”中断,它采用恢复调用rthw_interrupt_disable()函数前的中断状态,进行“使能”中断状态,如果调用rt_hw_interrupt_disable() 函数前是关中断状态,那么调用此函数后依然是关中断状态。level参数是上一次调用rt_hw_interrupt disable()时的返回值。
函数参数
- 参数 描述
- level 前一次rt_hw_interrupt_disable返回的中断状态。
函数返回
无
使用开关中断进行线程间同步的例子代码如下例代码所示:
- /* 代码清单:关闭中断进行全局变量的访问 */
- #include <rtthread.h>
- /* 同时访问的全局变量 */
- static rt_uint32_t cnt;
- void thread_entry(void* parameter)
- {
- rt_uint32_t no;
- rt_uint32_t level;
- no = (rt_uint32_t) parameter;
- while(1)
- {
- /* 关闭中断 */
- level = rt_hw_interrupt_disable();
- cnt += no;
- /* 恢复中断 */
- rt_hw_interrupt_enable(level);
- rt_kprintf("thread[%d]'s counter is %d\n", no, cnt);
- rt_thread_delay(no);
- }
- }
- /* 用户应用程序入口 */
- void rt_application_init()
- {
- rt_thread_t thread;
- /* 创建t1线程 */
- thread = rt_thread_create("t1", thread_entry, (void*)10,
- 512, 10, 5);
- if (thread != RT_NULL) rt_thread_startup(thread);
- /* 创建t2线程 */
- thread = rt_thread_create("t2", thread_entry, (void*)20,
- 512, 20, 5);
- if (thread != RT_NULL) rt_thread_startup(thread);
- }
使用中断锁来操作系统的方法可以应用于任何场合,且其他几类同步方式都是依赖于中断锁而实现的,可以说中断锁是最强大的和最高效的同步方法。只是使用中断锁最主要的问题在于,在中断关闭期间系统将不再响应任何中断,也就不能响应外部的事件。所以中断锁对系统的实时性影响非常巨大,当使用不当的时候会导致系统完全无实时性可言(可能导致系统完全偏离要求的时间需求);而使用得当,则会变成一种快速、高效的同步方式。
例如,为了保证一行代码(例如赋值)的互斥运行,最快速的方法是使用中断锁而不是信号量或互斥量:
- /* 关闭中断*/
- 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;的操作,使用中断锁将更为简洁快速。