顺序锁是一种轻量级锁,一般用于读多、写少。当写时总能获取到锁,读时需要忙等待直到写操作结束。
typedef struct {
unsigned sequence;
spinlock_t lock;
} seqlock_t;
声明:
seqlock_t seq=SEQLOCK_UNLOCKED;
DEFINE_SEQLOCK(seq);
seqlock_t seq;
seqlock_init(&seq);
写锁:
/* Lock out other writers and update the count.
* Acts like a normal spin_lock/unlock.
* Don't need preempt_disable() because that is in the spin_lock already.
*/
static inline void write_seqlock(seqlock_t *sl)
{
spin_lock(&sl->lock);
++sl->sequence;
smp_wmb();
}
static inline void write_sequnlock(seqlock_t *sl)
{
smp_wmb();
sl->sequence++;
spin_unlock(&sl->lock);
}
static inline int write_tryseqlock(seqlock_t *sl)
{
int ret = spin_trylock(&sl->lock);
if (ret) {
++sl->sequence;
smp_wmb();
}
return ret;
}
读锁:
/* Start of read calculation -- fetch last complete writer token */
static __always_inline unsigned read_seqbegin(const seqlock_t *sl)
{
unsigned ret;
repeat:
ret = sl->sequence;
smp_rmb();
if (unlikely(ret & 1)) {
cpu_relax();
goto repeat;
}
return ret;
}
/*
* Test if reader processed invalid data.
*
* If sequence value changed then writer changed data while in section.
*/
static __always_inline int read_seqretry(const seqlock_t *sl, unsigned start)
{
smp_rmb();
return (sl->sequence != start);
}
从上可以看出,写操作时,获取锁和释放锁只要配对,序号的值肯定是偶数。
读操作时,并没有锁的操作,而是只要判定序号的奇偶来判定是否有写操作在进行。
因此,可以认为读操作可以随时访问资源,只不过需要检查是否和写入者发生冲突,当发生冲突时,需要对资源重新访问。
另外,顺序锁可以在中断上下文中使用,原因是写操作使用的是自旋锁,读操作没有使用任何锁机制。不过和自旋锁一样,中断中必须使用禁止中断的版本。