关闭中断

关闭中断也叫中断锁,是禁止多任务访问临界区最简单的一种方式,即使是在分时操作系统中也是如此。当中断关闭的时候,就意味着当前任务不会被其他事件打断(因为整个系统已经不再响应那些可以触发线程重新调度的外部事件),也就是当前线程不会被抢占,除非这个任务主动放弃了处理器控制权。关闭中断/恢复中断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()时的返回值。

函数参数


  1. 参数 描述

  1. level 前一次rt_hw_interrupt_disable返回的中断状态。

函数返回

使用开关中断进行线程间同步的例子代码如下例代码所示:

  1. /* 代码清单:关闭中断进行全局变量的访问 */
  2. #include <rtthread.h>
  3.  
  4. /* 同时访问的全局变量 */
  5. static rt_uint32_t cnt;
  6. void thread_entry(void* parameter)
  7. {
  8. rt_uint32_t no;
  9. rt_uint32_t level;
  10.  
  11. no = (rt_uint32_t) parameter;
  12. while(1)
  13. {
  14. /* 关闭中断 */
  15. level = rt_hw_interrupt_disable();
  16. cnt += no;
  17. /* 恢复中断 */
  18. rt_hw_interrupt_enable(level);
  19.  
  20. rt_kprintf("thread[%d]'s counter is %d\n", no, cnt);
  21. rt_thread_delay(no);
  22. }
  23. }
  24.  
  25. /* 用户应用程序入口 */
  26. void rt_application_init()
  27. {
  28. rt_thread_t thread;
  29.  
  30. /* 创建t1线程 */
  31. thread = rt_thread_create("t1", thread_entry, (void*)10,
  32. 512, 10, 5);
  33. if (thread != RT_NULL) rt_thread_startup(thread);
  34.  
  35. /* 创建t2线程 */
  36. thread = rt_thread_create("t2", thread_entry, (void*)20,
  37. 512, 20, 5);
  38. if (thread != RT_NULL) rt_thread_startup(thread);
  39. }
  • 警告: 由于关闭中断会导致整个系统不能响应外部中断,所以在使用关闭中断做为互斥访问临界区的手段时,首先必须需要保证关闭中断的时间非常短,例如数条机器指令。

    使用场合

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

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

  1. /* 关闭中断*/
  2. level = rt_hw_interrupt_disable();
  3. a = a + value;
  4. /* 恢复中断*/
  5. rt_hw_interrupt_enable(level);

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

  1. /* 获得信号量锁*/
  2. rt_sem_take(sem_lock, RT_WAITING_FOREVER);
  3. a = a + value;
  4. /* 释放信号量锁*/
  5. rt_sem_release(sem_lock);

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