顺序锁是一种轻量级锁,一般用于读多、写少。当写时总能获取到锁,读时需要忙等待直到写操作结束。
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); }
从上可以看出,写操作时,获取锁和释放锁只要配对,序号的值肯定是偶数。
读操作时,并没有锁的操作,而是只要判定序号的奇偶来判定是否有写操作在进行。
因此,可以认为读操作可以随时访问资源,只不过需要检查是否和写入者发生冲突,当发生冲突时,需要对资源重新访问。
另外,顺序锁可以在中断上下文中使用,原因是写操作使用的是自旋锁,读操作没有使用任何锁机制。不过和自旋锁一样,中断中必须使用禁止中断的版本。