分类: LINUX
2009-10-22 20:44:33
读写锁,是自旋锁的一种衍生锁,为什么要衍生锁了,是因为自旋锁在多个执行单元在同时读写临界资源时都会被锁住,这样最多只能有一个执行单元拥有锁进而对资源进行操作,然而事实并非如此,在很多时候,同时读取临界资源是没有问题的,所以引入读写锁,他解决了读执行单元同时操作临界资源的问题,即允许读并发,但在写单元执行时最多允许一个进程访问临界资源。
定义和初始化:
rwlock_t my_rwlock=RW_LOCK_UNLOCKED; //静态初始化
rwlokc_t my_rwlock;
rwlock_init(&my_rwlock); //动态初始化
读锁定与解锁:
//读锁定与读解锁
void read_lock(rwlock_t *lock)
void read_unlock(rwlock_t *lock)
//相当于: read_lock()+local_irq_save()/local_irq_restore
void read_lock_irqsave(rwlock_t *lock,unsigned long flags)
void read_unlock_irqrestore(rwlock_t *lock,unsigned long flags)
//相当于:read_lock()+local_irq_disable()/local_irq_enable()
void read_lock_irq(rwlock_t *lock)
void read_unlock_irq(rwlock_t *lock)
//相当于:read_lock()+local_bh_disable()/local_bh_enable()
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)
//相当于: write_lock()+local_irq_save()/local_irq_restore
void write_lock_irqsave(rwlock_t *lock,unsigned long flags)
void write_unlock_irqrestore(rwlock_t *lock,unsigned long flags)
//相当于: write_lock()+local_irq_disable()/local_irq_enable()
void write_lock_irq(rwlock_t *lock)
void write_unlock_irq(rwlock_t *lock)
//相当于: write_lock()+local_bh_disable()/local_bh_enable()
void write_lock_bh(rwlock_t *lock)
void write_unlock_bh(rwlock_t *lock)
另外还有:int write_trylock(rwlock_t *lock) ,不管成功与否,都会立即返回。
一般有如下用法模型:
rwlock_t lock; //定义
read_init( &lock);
..........//临界资源
read_unlock(&lock);
//写时
write_lock_irqsave(&lock,flags);
..........//临界资源
write_unlock_irqrestroe(&lock,flags);
顺序锁(seqlock_t),对读写锁的一种优化,使用顺序锁时,读不会被写执行单元阻塞,也就是说,当向一个临界资源中写入的同时,也可以从此临界资源中读取,即实现同时读写,但是同时写不被允许。如果读执行单元在读操作期间,写执行单元已经嗯发生了写操作,那么,读执行单元必须重新开始,这样保证了数据的完整性,当然这种可能是微乎其微。顺序锁的性能是非常好的,同时他允许读写同时进行,大大的提高了并发性。
但是他有一个限制:共享资源不含有指针,因为写执行单元可能使得指针失效,但读执行单元如果正要访问该指针,将导致Oops( 网上搜索这个词的意思是:吃惊的感叹词。我理解为访问该指针将会导致意想不到的结果)。
写执行单元涉及到的一些相关操作:
void write_seqlock(seqlock_t *s1);
void write_sequnlock(seqlock_t *s1);
//宏调用,相当于:write_seqlock()+local_irq_save()
write_seqlock_irqsave(lock,flags)
write_sequnlock_irqrestore(lock,flags)
//宏调用,相当于:write_seqlock()+local_irq+disable()
write_seqlock_irq(lock)
write_sequnlock_irq(lock)
//宏调用,相当于:write_seqlock()+local_bh_disable()
write_seqlock_bh(lock)
write_sequnlock_bh(lock)
int write_tryseqlock(seqlock_t *s1),此函数和上面提到的类似。
写执行单元使用如下一种模式的顺序锁:
write_seqlock(&seqlock);
.........//写操作代码块
write_sequnlock(&seqlock);
读执行单元涉及如下顺序锁操作:
读开始:unsigned read_seqbegin(const seqlock_t *s1);//读执行单元在访问共享资源时要//调用该函数,返回锁s1的顺序号,
read_seqbegin_irqsave(lock,flags) //等同于:local_irq_save()+read_seqbegin()
重读:int read_seqretry(const seqlock_t *s1,unsigned iv) //在读结束后调用此函数来检///查,是否有写执行单元对资源进行操作,若有,则重新读。iv 为锁的顺序号。
代码段如下:
do{
seqnum=read_seqbegin(&seqlock);
//读操作代码段
...........
}while(read_seqretry(&seqlock,seqnum);