分类: LINUX
2008-08-01 18:19:38
一、定义:
/linux/include/asm-i386/rwsem.h
struct { signed long ; #define 0x00000000 #define 0x00000001 #define 0x0000ffff #define (-0x00010000) #define #define ( + ) ; struct ; #ifdef struct ; #endif }; |
二、作用:
与信号量类似,也是内核中一种互斥机制。与信号量相比,它允许
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);
该函数用于把写者降级为读者,这有时是必要的。因为写者是排他性的,因此在写者保持读写信号量期间,任何读者或写者都将无法访问该读写信号量保护的共享资源,对于那些当前条件下不需要写访问的写者,降级为读者将,使得等待访问的读者能够立刻访问,从而增加了并发性,提高了效率。
niutao.linux2008-08-01 22:08:36
信号量的睡眠特性,使得信号量适用于锁会被长时间持有的情况;详细参见: http://blog.chinaunix.net/u2/73528/showart_1098606.html 读写信号量用在有多个读者(读取该临界资源)的情况,可以增强读的并发,提高系统速度。例如在注册kobject结构(kobject_add)时会用到。