1 自旋锁简介
自旋锁它是为为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。
2 自旋锁适用情况
自旋锁比较适用于锁使用者保持锁时间比较短的情况。正是由于自旋锁使用者一般保持锁时间非常短,因此选择自旋而不是睡眠是非常必要的,自旋锁的效率远高于互斥锁。信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因此只能在进程上下文使用,而自旋锁适合于保持时间非常短的情况,它可以在任何上下文使用。如果被保护的共享资源只在进程上下文访问,使用信号量保护该共享资源非常合适,如果对共享资源的访问时间非常短,自旋锁也可以。但是如果被保护的共享资源需要在中断上下文访问(包括底半部即中断处理句柄和顶半部即软中断),就必须使用自旋锁。自旋锁保持期间是抢占失效的,而信号量和读写信号量保持期间是可以被抢占的。自旋锁只有在内核可抢占或SMP(多处理器)的情况下才真正需要,在单CPU且不可抢占的内核下,自旋锁的所有操作都是空操作。另外格外注意一点:自旋锁不能递归使用。
3 自旋锁 使用
自旋锁定义: linux/Spinlock.h
在Linux中,每个自旋锁都用spinlock_t结构表示: typedef struct { raw_spinlock_t raw_lock; #if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) unsigned int break_lock; #endif #ifdef CONFIG_DEBUG_SPINLOCK unsigned int magic, owner_cpu; void *owner; #endif #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif } spinlock_t; typedef struct{ volatile unsigned int slock; } raw_spinlock_t;
定义和初始化 spinlock_t my_lock = SPIN_LOCK_UNLOCKED; void spin_lock_init(spinlock_t *lock); 自旋锁操作: //加锁一个自旋锁函数 void spin_lock(spinlock_t *lock); //获取指定的自旋锁 void spin_lock_irq(spinlock_t *lock); //禁止本地中断获取指定的锁 void spin_lock_irqsave(spinlock_t *lock, unsigned long flags); //保存本地中断的状态,禁止本地中断,并获取指定的锁 void spin_lock_bh(spinlock_t *lock) //安全地避免死锁, 而仍然允许硬件中断被服务 //释放一个自旋锁函数 void spin_unlock(spinlock_t *lock); //释放指定的锁 void spin_unlock_irq(spinlock_t *lock); //释放指定的锁,并激活本地中断 void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags); //释放指定的锁,并让本地中断恢复到以前的状态 void spin_unlock_bh(spinlock_t *lock); //对应于spin_lock_bh //非阻塞锁 int spin_trylock(spinlock_t *lock); //试图获得某个特定的自旋锁,如果该锁已经被争用,该方法会立刻返回一个非0值, //而不会自旋等待锁被释放,如果成果获得了这个锁,那么就返回0. //而不会自旋等待锁被释放,如果成果获得了这个锁,那么就返回0. int spin_trylock_bh(spinlock_t *lock); //这些函数成功时返回非零( 获得了锁 ), 否则 0. 没有"try"版本来禁止中断. //其他 int spin_is_locked(spinlock_t *lock); //和try_lock()差不多,如果自旋锁被置为1(未锁),返回0;否则,返回1 zz总结