Linux其他类型锁

2021/12/1 7:11:11

本文主要是介绍Linux其他类型锁,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一、读写自旋锁

现在有个学生信息表,此表存放着学生的年龄、家庭住址、班级等信息,此表可以随时被修改和读取。此表肯定是数据,那么必须要对其进行保护,如果现在使用自旋锁对其进行保护。每次只能一个读操作或者写操作,但是,实际上此表是可以并发读取的。只需要保证在修改此表的时候没人读取,或者在其他人读取此表的时候没有人修改此表就行了。也就是此表的读和写不能同时进行,但是可以多人并发的读取此表。像这样,当某个数据结构符合读/写或生产者/消费者模型的时候就可以使用读写自旋锁读写自旋锁为读和写操作提供了不同的锁,一次只能允许一个写操作,也就是只能一个线程持有写锁,而且不能进行读操作。但是当没有写操作的时候允许一个或多个线程持有读锁,可以进行并发的读操作。Linux内核使用rwlock_t结构体表示读写锁,结构体定义如下(删除了条件编译):

typedef struct {
arch_rwlock_t raw_lock;
}rwlock t;

读写锁操作API函数分为两部分,一个是给读使用的,一个是给写使用的,这些API函数如下表所示:

函数描述
DEFINE_RWLOCK(rwlock_t lock)定义并初始化读写锁。
void rwlock_init(rwlock_t *lock)初始化读写锁。

读锁

函数描述
void read_lock(rwlock_t *lock)获取读锁。
void read_unlock(rwlock_t *lock)释放读锁。
void read_lock_irq(rwlock_t *lock)禁止本地中断,并且获取读锁。
void read_unlock_irq(rwlock_t *lock)打开本地中断,并且释放读锁。
void read_lock_irqsave(rwlock_t* lock,unsigned long flags)保存中断状态,禁止本地中断,并获取读锁。
void read_unlock_irqrestore(rwlock_t *lock,unsigned long flags)将中断状态恢复到以前的状态,并且激活本地中断,释放读锁。
void read_lock_bh(rwlock_t *lock)关闭下半部,并获取读锁。
void read_unlock_bh(rwlock_t*lock)打开下半部,并释放读锁。

写锁

函数描述
void write_lock(rwlock_t *lock)获取写锁。
void write_unlock(rwlock_t *lock)释放写锁。
void write_lock_irq(rwlock_t *lock)禁止本地中断,并且获取写锁。
void write_unlock_irq(rwlock_t *lock)打开本地中断,并且释放写锁。
void write_lock_irqsave(rwlock_t *lock,unsigned long flags)保存中断状态,禁止本地中断,并获取写锁。
void write_unlock_irqrestore(rwlock_t *lock,unsigned long flags)将中断状态恢复到以前的状态,并且激活本地中断,释放读锁。
void write_lock_bh(rwlock_t *lock)关闭下半部,并获取读锁。
void write_unlock_bh(rwlock_t *lock)打开下半部,并释放读锁。

二、顺序锁

顺序锁在读写锁的基础上衍生而来的,使用读写锁的时候读操作和写操作不能同时进行。使用顺序锁的话可以允许在写的时候进行读操作,也就是实现同时读写,但是不允许同时进行并发的写操作。虽然顺序锁的读和写操作可以同时进行,但是如果在读的过程中发生了写操作,最好重新进行读取,保证数据完整性。顺序锁保护的资源不能是指针,因为如果在写操作的时候可能会导致指针无效,而这个时候恰巧有读操作访问指针的话就可能导致意外发生,比如读取野指针导致系统崩溃。Linux内核使用seqlock_t结构体表示顺序锁,结构体定义如下:

typedef struct {
	struct seqcount seqcount;
	spinlock_t lock;
} seqlock_t;

顺序锁的API函数如下表所示:

函数描述
DEFINE_SEQLOCK(seqlock_t sl)定义并初始化顺序锁。
void seqlock_ini seqlock_t *sl)初始化顺序锁。

顺序锁写操作

函数描述
void write_seqlock(seqlock_t *sl)获取写顺序锁。
void write_sequnlock(seqlock_t *sl)释放写顺序锁。
void write_seqlock_irq(seqlock_t *sl)禁止本地中断,并且获取写顺序锁。
void write_sequnlock_irq(seqlock_t *sl)打开本地中断,并且释放写顺序锁。
void write_seqlock_irqsave(seqlock_t *sl,unsigned long flags)保存中断状态,禁止本地中断,并获取写顺序锁。
void write_sequnlock_irqrestore(seqlock_t *sl,unsigned long flags)将中断状态恢复到以前的状态,并且激活本地中断,释放写顺序锁。
void write_seqlock_bh(seqlock_t *sl)关闭下半部,并获取写读锁。
void write_sequnlock_bh(seqlock_t *sl)打开下半部,并释放写读锁。

顺序锁读操作

函数描述
unsigned read_seqbegin(const seqlock_t *sl)读单元访问共享资源的时候调用此函数,此函数会返回顺序锁的顺序号。
unsigned read_seqretry(const seqlock_t *sl,unsigned start)读结束以后调用此函数检查在读的过程中有没有对资源进行写操作,如果有的话就要重读。

三、自旋锁使用注意事项

  • ①、因为在等待自旋锁的时候处于“自旋”状态,因此锁的持有时间不能太长,一定要短,否则的话会降低系统性能。如果临界区比较大,运行时间比较长的话要选择其他的并发处理方式,比如稍后要讲的信号量和互斥体。
  • ②、自旋锁保护的临界区内不能调用任何可能导致线程休眠的API函数,否则的话可能导致死锁。
  • ③、不能递归申请自旋锁,因为一旦通过递归的方式申请一个你正在持有的锁,那么你就必须“自旋”,等待锁被释放,然而你正处于“自旋”状态,根本没法释放锁。结果就是自己把自己锁死了!
  • ④、在编写驱动程序的时候必须考虑到驱动的可移植性,因此不管用的是单核的还是多核的SOC,都将其当做多核SOC来编写驱动程序。


这篇关于Linux其他类型锁的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程