Let's go!!!!!
分类: LINUX
2018-11-23 17:23:21
自旋锁 | ||
自旋锁主要针对 SMP 或单 CPU 但内核可抢占的情况,自旋锁持有期间内核的抢占将被禁止。尽管用了自旋锁可以保证临界区不受别的 CPU 和本 CPU 内的抢占进程打扰,但是得到锁的代码路径在执行临界区的时候还可能受到中断和底半部(BH)的影响。为了防止这种影响,就需要用到自旋锁的衍生 。 spinlock_t lock; spin_lock_init(&lock); |
||
spin_lock(lock) | spin_trylock(lock) |
spin_lock_irq() = spin_lock() + local_irq_disable() spin_unlock_irq() = spin_unlock() + local_irq_enable() spin_lock_irqsave() = spin_unlock() + local_irq_save() spin_unlock_irqrestore() = spin_unlock() + local_irq_restore() spin_lock_bh() = spin_lock() + local_bh_disable() spin_unlock_bh() = spin_unlock() + local_bh_enable() |
该宏用于获得自旋锁 lock,如果能够立即获得锁,它就马上返回,否则,它将自旋在那里,直到该自 旋锁的保持者释放; |
该宏尝试获得自旋锁 lock,如果能立即获得锁,它获得锁并返回真,否则立即返回假,实际上不再“在 原地打转”; |
|
spin_unlock(lock) | ||
死锁 |
自旋锁实际上是忙等锁,当锁不可用时,CPU 一直循环执行“测试并设置”该锁直到可用而取得 该锁,CPU 在等待自旋锁时不做任何有用的工作,仅仅是等待。因此,只有在占用锁的时间极短 的情况下,使用自旋锁才是合理的。当临界区很大或有共享设备的时候,需要较长时间占用锁 使用自旋锁会降低系统的性能。 |
|
自旋锁可能导致系统死锁。引发这个问题最常见的情况是递归使用一个自旋锁,即如果一个已经 拥有某个自旋锁的CPU 想第二次获得这个自旋锁,则该CPU 将死锁。此外,如果进程获得自旋 锁之后再阻塞,也有可能导致死锁的发生。copy_from_user()、copy_to_user()和kmalloc()等函数 都有可能引起阻塞,因此在自旋锁的占用期间不能调用这些函数。 |
||
信号量 | ||
与自旋锁相同,只有得到信号量的进程才能执行临界区代码。但是,与自旋锁不同的是,当获取不到信号量时,进程不会原地打转而是进入休眠等待状态。 struct semaphore sem;sema_init (&sem,1); |
||
down(&sem) | down_interruptible(&sem) | down_trylock(&sem) |
数用于获得信号量sem,它会导致睡眠,因此不能在中断上下文使用。 |
因为down()而进入睡眠状态的进程不能被信号打断,而因为 down_interruptible()而进入睡眠状态的进程能被信号打断,信号也会导致该函数返回,这时候函数的返回值 非0。 |
该函数尝试获得信号量sem,如果能够立刻获得,它就获得该信号量并返回0,否则,返回非0 值。它不会导致调用者睡眠,可以在中断上下文使用。 |
up(&sem) | ||
信号量是进程级的,用于多个进程之间对资源的互斥,虽然也是在内核中,但是该内核执行路径是以进程的身份,代表进程来争夺资源的。如果竞争失败,会发生进程上下文切换,当前进程进入睡眠状态,CPU 将运行其他进程。鉴于进程上下文切换的开销也很大,因此,只有当进程占用资源时间较长时,用信号量才是较好的选择。 当所要保护的临界区访问时间比较短时,用自旋锁是非常方便的,因为它节省上下文切换的时间。但是CPU 得不到自旋锁会在那里空转直到其他执行单元解锁为止,所以要求锁不能在临界区里长时间停留,否则会降低系统的效率。 1.信号量所保护的临界区可包含可能引起阻塞的代码,而自旋锁则绝对要避免用来保护包含这样代码的临界区。因为阻塞意味着要进行进程的切换,如果进程被切换出去后,另一个进程企图获取本自旋锁,死锁就会发生。 2.信号量存在于进程上下文,因此,如果被保护的共享资源需要在中断或软中断情况下使用,则在信号量和自旋锁之间只能选择自旋锁。 |
||