一、定义:
/linux/include/asm-i386/rwsem.h
55struct rw_semaphore {
56 signed long count;
57#define RWSEM_UNLOCKED_VALUE 0x00000000
58#define RWSEM_ACTIVE_BIAS 0x00000001
59#define RWSEM_ACTIVE_MASK 0x0000ffff
60#define RWSEM_WAITING_BIAS (-0x00010000)
61#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
62#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
63 spinlock_t wait_lock;
64 struct list_head wait_list;
65#ifdef CONFIG_DEBUG_LOCK_ALLOC
66 struct lockdep_map dep_map;
67#endif
68};
二、作用:
与信号量类似,也是内核中一种互斥机制。与信号量相比,它允许N个读执行单元同时访问共享资源,但最多只能有一个写执行单元。因此是一种相对放宽条件的力度稍大于信号量的互斥机制。
三、特点:
读写信号量对访问者进行了细分,或者为读者,或者为写者,读者在保持读写信号量期间只能对该读写信号量保护的共享资源进行读访问,如果一个任务除 了需要读,可能还需要写,那么它必须被归类为写者,它在对共享资源访问之前必须先获得写者身份,写者在发现自己不需要写访问的情况下可以降级为读者。读写 信号量同时拥有的读者数不受限制,也就说可以有任意多个读者同时拥有一个读写信号量。
如果一个读写信号量当前没有被写者拥有并且也没有 写者等待读者释放信号量,那么任何读者都可以成功获得该读写信号量;否则,读者必须被挂起直到写者释放该信号量。如果一个读写信号量当前没有被读者或写者 拥有并且也没有写者等待该信号量,那么一个写者可以成功获得该读写信号量,否则写者将被挂起,直到没有任何访问者。因此,写者是排他性的,独占性的。
读写信号量有两种实现,一种是通用的,不依赖于硬件架构,因此,增加新的架构不需要重新实现它,但缺点是性能低,获得和释放读写信号量的开销大;另一种 是架构相关的,因此性能高,获取和释放读写信号量的开销小,但增加新的架构需要重新实现。在内核配置时,可以通过选项去控制使用哪一种实现。
四、各字段详解:
1、signed long count;
实际上是两个16位的计数器。其中高16位以二进制补码形式存放非等待写者进程的总数(0或1)或等待的写内核控制路径数。低16位存放非等待的读者或写者进程的总数。
2、spinlock_t wait_lock;
一个自旋锁,用于保护等待队列连表和rw_semaphore结构本身。
3、struct list_head wait_list;
指向等待进程的链表。链表中的每个元素都是一个rwsem_waiter结构,该结构包含一个指针和一个标志,指针指向睡眠进程的描述符,标志表示进程是为读需要信号量还是为写需要信号量。
五、操作:
1、定义并初始化:
(1)
struct rw_semaphore rwsem;
init_rwsem(&rwsem);
直接定义并调用init_rwsem()初始化。init_rwsem()实际上是一个宏,调用它会将读写信号量count字段置为0,wait_lock自旋锁置为未锁,wait_list置为空链表。如此以来该读写信号量就可以被获取。
(2)
DECLARE_RWSEM(name);
静态定义并初始化读写信号量name,结果与第一种定义方式相同。
2、读信号量操作:
void down_read(struct rw_semaphore *sem);
int read_trylock(struct rw_semaphore *sem);
void up_read(struct rw_semaphore *sem);
这三个函数用于操作读信号量。
其中down_read()函数作用是读者调用该函数来得到读写信号量sem。该函数会导致调用者睡眠,因此只能在进程上下文使用。
read_trylock()函数类似于down_read,只是它不会导致调用者睡眠。它尽力得到读写信号量sem,如果能够立即得到,它就得到该读写信号量,并且返回1,否则表示不能立刻得到该信号量,返回0。因此,它也可以在中断上下文使用。
up_read()函数的作用是读者使用该函数释放读写信号量sem。它与down_read或down_read_trylock配对使用。如果down_read_trylock返回0,不需要调用up_read来释放读写信号量,因为根本就没有获得信号量。
3、写信号量操作:
void down_write(struct rw_semaphore *sem);
int down_write_trylock(struct rw_semaphore *sem);
void up_write(struct rw_semaphore *sem);
这三个函数用于写信号量获取操作。
其中down_write()函数,写者使用该函数来得到读写信号量sem,它也会导致调用者睡眠,因此只能在进程上下文使用。
down_trywrite()函数类似于down_write,只是它不会导致调用者睡眠。该函数尽力得到读写信号量,如果能够立刻获得,就获得该读写信号量并且返回1,否则表示无法立刻获得,返回0。它可以在中断上下文使用。
up_write(),写者调用该函数释放信号量sem。它与down_write或down_write_trylock配对使用。如果down_write_trylock返回0,不需要调用up_write,因为返回0表示没有获得该读写信号量。
4、其他函数:
void downgrade_write(struct rw_semaphore *sem);
该函数用于把写者降级为读者,这有时是必要的。因为写者是排他性的,因此在写者保持读写信号量期间,任何读者或写者都将无法访问该读写信号量保护的共享资源,对于那些当前条件下不需要写访问的写者,降级为读者将,使得等待访问的读者能够立刻访问,从而增加了并发性,提高了效率。
参考:
阅读(850) | 评论(0) | 转发(0) |