自旋锁的一个特性就是忙等待,循环过程中会大量消耗CPU,可以在中断上下文中使用。
只要有一个任务持有自旋锁,其他任务就可能在等待的时候自旋,使用自旋锁要确保不会长时间持有。
在单处理器系统上,应该使用spin_lock_irqsave()和spin_lock_irqrestore(),禁用处理器上中断,防止中断并发。
自旋锁与互斥锁的比较:
1、互斥锁保护进程关键资源,而自旋锁保护IRQ处理程序的关键部分。
2、互斥锁让竞争者在获得锁之前睡眠,而自旋锁在获得锁之前一直自旋循环(消耗CPU)
3、自旋锁不能长时间持有,因为等待者在等待取锁期间会浪费CPU时间,互斥锁可以长时间持有,竞争者被放入等待队列中进入睡眠状态。
持有自旋锁的线程被禁止抢占,自旋锁抢占者没有被禁止抢占。
以下为一些常见自旋锁加解锁相关函数
// 主要数据结构
typedef struct spinlock {
union {
struct raw_spinlock rlock;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))
struct {
u8 __padding[LOCK_PADSIZE];
struct lockdep_map dep_map;
};
#endif
};
} spinlock_t;
// 静态初始化
#define DEFINE_SPINLOCK(x) spinlock_t x = __SPIN_LOCK_UNLOCKED(x)
// 动态初始化
#define spin_lock_init(_lock) \
do { \
spinlock_check(_lock); \
raw_spin_lock_init(&(_lock)->rlock); \
} while (0)
// 获取给定的自旋锁
static __always_inline void spin_lock(spinlock_t *lock)
{
raw_spin_lock(&lock->rlock);
}
// 释放锁给定的自旋锁
static __always_inline void spin_unlock(spinlock_t *lock)
{
raw_spin_unlock(&lock->rlock);
}
// 禁止软件中断并且获取给定的自旋锁
static __always_inline void spin_lock_bh(spinlock_t *lock)
{
raw_spin_lock_bh(&lock->rlock);
}
// 释放给定的自旋锁并且启动软件中断
static __always_inline void spin_unlock_bh(spinlock_t *lock)
{
raw_spin_unlock_bh(&lock->rlock);
}
// 禁止本地处理器上的中断,并且不保存之前的中断状态的标识
static __always_inline void spin_lock_irq(spinlock_t *lock)
{
raw_spin_lock_irq(&lock->rlock);
}
static __always_inline void spin_unlock_irq(spinlock_t *lock)
{
raw_spin_unlock_irq(&lock->rlock);
}
// 禁止本地处理器上的中断,并且保存之前的中断状态的标识
// flags类型为:unsigned long
#define spin_lock_irqsave(lock, flags) \
do { \
raw_spin_lock_irqsave(spinlock_check(lock), flags); \
} while (0)
static __always_inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
{
raw_spin_unlock_irqrestore(&lock->rlock, flags);
}
自旋锁初始化的两种方式:
1、动态初始化
spinlock_t lock;
spin_lock_init (&lock);
2、静态初始化
DEFINE_SPINLOCK(lock);
以下为一些自旋锁的相关辅助函数
// 判断自旋锁是否已经被持有
/**
* spin_is_locked() - Check whether a spinlock is locked.
* @lock: Pointer to the spinlock.
*
* This function is NOT required to provide any memory ordering
* guarantees; it could be used for debugging purposes or, when
* additional synchronization is needed, accompanied with other
* constructs (memory barriers) enforcing the synchronization.
*
* Returns: 1 if @lock is locked, 0 otherwise.
*
* Note that the function only tells you that the spinlock is
* seen to be locked, not that it is locked on your CPU.
*
* Further, on CONFIG_SMP=n builds with CONFIG_DEBUG_SPINLOCK=n,
* the return value is always 0 (see include/linux/spinlock_up.h).
* Therefore you should not rely heavily on the return value.
*/
static __always_inline int spin_is_locked(spinlock_t *lock)
{
return raw_spin_is_locked(&lock->rlock);
}
自旋锁使用流程
spinlock_t my_spin_lock;
spin_lock_init(my_spin_lock);
spin_lock(&my_spin_lock);
spin_unlock(&my_spin_lock);
读写自旋锁的使用场景:对临界区读多写少的情况。
// 主要数据结构
typedef struct {
arch_rwlock_t raw_lock;
#ifdef CONFIG_DEBUG_SPINLOCK
unsigned int magic, owner_cpu;
void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
} rwlock_t;
// 读写自旋锁的初始化
# define rwlock_init(lock) \
do { \
static struct lock_class_key __key; \
\
__rwlock_init((lock), #lock, &__key); \
} while (0)
// 与普通自选锁一样,也存在以下函数
#define write_lock(lock) _raw_write_lock(lock)
#define read_lock(lock) _raw_read_lock(lock)
#define read_lock_irq(lock) _raw_read_lock_irq(lock)
#define read_lock_bh(lock) _raw_read_lock_bh(lock)
#define write_lock_irq(lock) _raw_write_lock_irq(lock)
#define write_lock_bh(lock) _raw_write_lock_bh(lock)
#define read_unlock(lock) _raw_read_unlock(lock)
#define write_unlock(lock) _raw_write_unlock(lock)
#define read_unlock_irq(lock) _raw_read_unlock_irq(lock)
#define write_unlock_irq(lock) _raw_write_unlock_irq(lock)