内核中的同步问题

内核中的同步问题是一个很复杂,而且经常让人感到崩溃的问题,即使是应用程序,多线程也是一个复杂的问题。一般的同步方法包括有锁机制,互斥量,信号量等。而各种应用场景下的方法的选择,尤其是涉及不同的上下文和不同的体系结构时,这个问题会更加复杂。

 

锁和互斥量是保护临界区的两种基本方法。锁保证在同一时刻只有一个线程能够进入临界区,其他线程只有在这个线程退出后在能进入临界区。其使用方法很简单,

 

而 互斥量和锁的功能差不多,区别在于等待锁的线程总是在进行忙等待,而等待互斥量的线程会进入睡眠状态,直到其他线程释放互斥量。一般情况下,如果线程需要 睡眠,只能使用互斥量,获取锁后不能调度,抢占或者睡眠。而在中断处理函数中,由于其不能睡眠,所以只能使用锁机制。互斥量的使用方法如下:

 

互斥量接口取代了原来的信号量接口,当然原来的接口还可以使用,但谁也不敢保证未来怎么样。

 

 

随着操作系统以及系统结构的发展,这种同步问题越来越复杂。操作系统方面,内核是不是能够抢占,程序运行在什么上下文环境,系统结构方面,单核和多核的区别等。根据这些,可以分为多个情况:

(1)进程上下文和中断上下文 && 单处理器 && 非抢占内核

因为中断发生时要优先处理中断,因此中断处理程序不需要采取多余的措施,而对于运行在进程上下文的普通进程来说,则需要在执行时屏蔽中断。

假设A,B为运行在进程上下文的两个进程,而C运行在中断上下文,三个进程共享一个临界区。一旦C开始执行,除非C运行结束或者主动让出CPU,否则C会一直运行下去,因此C不用担心A,B带来的影响。再来看A,B,两者也是无须担心对方的,因为内核时非抢占的,唯一可以干扰他们执行的,只有中断处理程序,如C。如果A,B,C三者试图进入同一个临界区,则只需考虑A,B在临界区内被C抢占的情况。假设A已经进入临界区内,这意味着它已经成功获得了锁,此时中断发生,程序C开始执行,由于C无法获得锁,则此时将造成死锁。因此,A,B在进入临界区前,需要屏蔽中断。如下:

如果考虑到A在屏蔽中断之前,中断已被屏蔽,那么local_irq_enable()的调用可能造成影响,因此更妥善的方法时屏蔽中断时记录下中断屏蔽字,然后退出临界区后恢复中断屏蔽字。如下

 

(2)进程上下文和中断上下文 && 单处理器 && 抢占内核

和第一种情况类似,这种情况下屏蔽中断依然是必需的。但是,内核的可抢占特性增加了一种情况,就是A,B也可能在对方与临界区卿卿我我时横刀夺爱,所以此时A,B此时也要防止对方第三者插足,方法就是在进入临界区之前不仅要屏蔽中断,还要禁止内核抢占。

 

 

在上面的函数spin_lock_irqsave中不光屏蔽了中断,还禁止内核抢占。内核通过一个特定变量来确定当前是否可以进行抢占,只有当这个变量等于零时,内核才允许抢占。在spin_lock_irqsave()中调用了preempt_disable()函数,这个函数增加这个变量的值(加一),而在spin_unlock_irqrestore中调用函数preempt_enable()减少这个变量的值(减一)。

 

上面的情况下,锁的功能好像被弱化了,其实屏蔽中断和禁止抢占都是类似锁的功能----防止多个进程同时进入临界区。

 

(3)进程上下文和中断上下文 && 多处理器 && 抢占内核

上面的两种情况下,C无须考虑A,B带来的影响。而当内核运行在对称多处理器的机器上,由于可能有程序同时运行(这是真正的并行),所以中断处理程序C在进入临界区前,也要获取锁,以免A,B在其他处理器上运行并进入临界区而产生冲突。

 

至于A,B,因为锁机制的实现时SMP安全的,所以其执行没有变化,和(2)中一样。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值