读写信号量的相关API有:
DECLARE_RWSEM(name)
该宏声明一个读写信号量name并对其进行初始化。
void init_rwsem(struct rw_semaphore *sem);
该函数对读写信号量sem进行初始化。
void down_read(struct rw_semaphore *sem);
读者调用该函数来得到读写信号量sem。该函数会导致调用者睡眠,因此只能在进程上下文使用。
int down_read_trylock(struct rw_semaphore *sem);
该函数类似于down_read,只是它不会导致调用者睡眠。它尽力得到读写信号量sem,如果能够立即得到,它就得到该读写信号量,并且返回1,否则表示不能立刻得到该信号量,返回0。因此,它也可以在中断上下文使用。
void down_write(struct rw_semaphore *sem);
写者使用该函数来得到读写信号量sem,它也会导致调用者睡眠,因此只能在进程上下文使用。
int down_write_trylock(struct rw_semaphore *sem);
该函数类似于down_write,只是它不会导致调用者睡眠。该函数尽力得到读写信号量,如果能够立刻获得,就获得该读写信号量并且返回1,否则表示无法立刻获得,返回0。它可以在中断上下文使用。
void up_read(struct rw_semaphore *sem);
读者使用该函数释放读写信号量sem。它与down_read或down_read_trylock配对使用。如果down_read_trylock返回0,不需要调用up_read来释放读写信号量,因为根本就没有获得信号量。
void up_write(struct rw_semaphore *sem);
写者调用该函数释放信号量sem。它与down_write或down_write_trylock配对使用。如果down_write_trylock返回0,不需要调用up_write,因为返回0表示没有获得该读写信号量。
void downgrade_write(struct rw_semaphore *sem);
该函数用于把写者降级为读者,这有时是必要的。因为写者是排他性的,因此在写者保持读写信号量期间,任何读者或写者都将无法访问该读写信号量保护的共享资源,对于那些当前条件下不需要写访问的写者,降级为读者将,使得等待访问的读者能够立刻访问,从而增加了并发性,提高了效率。
读写信号量适于在读多写少的情况下使用,在linux内核中对进程的内存映像描述结构的访问就使用了读写信号量进行保护。
究竟什么时候使用自旋锁什么时候使用信号量,下面给出建议的方案
当对低开销、短期、中断上下文加锁,优先考虑自旋锁;当对长期、持有锁需要休眠的任务,优先考虑信号量。