Home 关于local_irq_save(了解)
Post
Cancel

关于local_irq_save(了解)

在内核中提供了一些宏定义,可以帮助禁用本地cpu的外部中断,对与解决并发引起的竞争问题有些帮助。

几个宏定义

1
2
3
4
5
6
7
8
9
10
local_irq_enable()	
local_irq_disable()	
local_irq_save(flags)
local_irq_restore(flags) 

//example
unsigned long flags;
local_irq_save(flags);
// 在这里执行需要禁用本地中断的代码
local_irq_restore(flags);

这几个宏定义是用来禁用/开启本地中断(外部中断),并可以保存中断状态。该几个宏定义的实现是和硬件架构相关的, 不同的cpu架构,其中断操作的指令也不同,具体实现也不同。linux使用统一的宏定义来兼容。

·local_irq_enable()local_irq_disable()用于开启和禁用本地cpu的外部中断,默认是打开的。 由于通常是临时禁用,运行一段代码后重新打开,所以需要保存中断状态,所以通常使用下面两个宏定义 local_irq_save(flags)local_irq_restore(flags)

该几个宏定义可以解决一部分并发导致的竞争问题,但是有限的,需要注意,

  1. 该宏定义仅禁用外部中断,执行的线程仍可能被抢占。对于可抢占式的调度器,(如linux默认), 禁用外部中断后,执行中的线程仍可能被调出调度器。 如果其他线程(无论是在该cpu核上还是在其他cpu核上)也有访问共享资源,是不能解决竞争问题的。
  2. 仅禁用本地的外部中断,中断处理服务函数仍可能会在其他cpu核心上执行,如果访问了共享资源,同样会有竞争问题。 中断处理函数通常注册到某中断向量上,和IRQ line绑定。当中断来临时,内核通常根据情况选一个核心来执行中断处理函数, 这是内核调度器决定的。除非通过CPU 亲和力绑定到某特定cpu核心上。

鉴于以上两点原因,该宏定义对并发的保护是很有限的。因为该宏保护的代码可以被其他核心上的中断或抢占代码打断,它只禁用本地 中断,不是全局的,也没有禁用抢占。在最早的单核不可抢占调度系统中,用这个可以实现并发访问的保护,(即临界代码),现在基本不可能。

为了确保在多核系统中的临界区代码不会被中断或抢占打断,除了使用local_irq_save禁用本地中断外,还需要采取其他措施,如使用自旋锁或其他同步机制。 或者,可以使用禁用抢占的机制(如preempt_disable())来阻止其他核心上的抢占。具体还要看有哪些代码会访问共享资源。需要根据具体的需求和场景, 结合适当的同步机制来保护临界区代码,以确保在多核系统中不被中断或抢占打断。

另外,由于禁用外部中断对系统性能也有影响,所以关开中断之间的执行代码不易时间过长。所以不建议使用。

This post is licensed under CC BY 4.0 by the author.

内核-互斥与同步机制

内核-spinlock(自旋锁)