第5章:并发与竞态条件-5:Reader/Writer Semaphores

In continuation of the previous text第5章:并发与竞态条件-4:Using Semaphores in scull, let's GO ahead.

Reader/Writer Semaphores

Semaphores perform mutual exclusion for all callers, regardless of what each thread may want to do. Many tasks break down into two distinct types of work, however: tasks that only need to read the protected data structures and those that must make changes. It is often possible to allow multiple concurrent readers, as long as nobody is trying to make any changes. Doing so can optimize performance significantly; read-only tasks can get their work done in parallel without having to wait for other readers to exit the critical section.

The Linux kernel provides a special type of semaphore called a rwsem (or “reader/writer semaphore”) for this situation. The use of rwsems in drivers is relatively rare, but they are occasionally useful.

普通信号量会对所有调用者进行互斥限制,无论线程要执行的操作类型。但许多任务可分为两类:仅需读取受保护数据结构的任务,和必须修改数据的任务。通常情况下,允许多个读线程并发访问是安全的 —— 只要没有写线程在执行修改操作。这种设计能显著优化性能:只读任务无需等待其他读线程退出临界区,可并行完成工作。

Linux 内核为此场景提供了一种特殊的信号量,称为 rwsem(读写信号量)。驱动中使用 rwsem 的场景相对少见,但在特定情况下非常实用。

Code using rwsems must include <linux/rwsem.h>. The relevant data type for reader/writer semaphores is struct rw_semaphore; an rwsem must be explicitly initialized at runtime with

使用 rwsem 的代码必须包含 <linux/rwsem.h> 头文件。读写信号量的相关类型是 struct rw_semaphore,必须在运行时通过以下函数显式初始化:

void init_rwsem(struct rw_semaphore *sem);

A newly initialized rwsem is available for the next task(reader or writer) that comes along. The interface for code needing read-only access is:

新初始化的 rwsem 处于可用状态,可被后续的读线程或写线程获取。需要只读访问受保护资源的线程,使用以下接口:

void down_read(struct rw_semaphore *sem);
int down_read_trylock(struct rw_semaphore *sem);
void up_read(struct rw_semaphore *sem);

A call to down_read provides read-only access to the protected resources, possibly concurrently with other readers. Note that down_read may put the calling process into an uninterruptible sleep. down_read_trylock will not wait if read access is unavailable; it returns nonzero if access was granted, 0 otherwise. Note that the convention for down_read_trylock differs from that of most kernel functions, where success is indicated by a return value of 0. A rwsem obtained with down_read must eventually be freed with up_read.

  • down_read:获取读锁,允许与其他读线程并发访问。该函数可能让调用进程进入不可中断睡眠

  • down_read_trylock:尝试获取读锁,不会等待。若获取成功返回非零值,失败返回 0(注意:这与内核多数函数 “返回 0 表示成功” 的惯例不同)。

  • up_read:释放读锁,必须与 down_read 或成功的 down_read_trylock 成对调用。

The interface for writers is similar:

需要修改受保护资源的线程,使用以下接口:

void down_write(struct rw_semaphore *sem);
int down_write_trylock(struct rw_semaphore *sem);
void up_write(struct rw_semaphore *sem);
void downgrade_write(struct rw_semaphore *sem);

down_write, down_write_trylock, and up_write all behave just like their reader counterparts, except, of course, that they provide write access. If you have a situation where a writer lockis needed for a quickchange, followed by a longer period of read only access, you can use downgrade_write to allow other readers in once you have finished making changes.

  • down_write:获取写锁,排他性访问(禁止其他读线程和写线程同时访问),可能进入不可中断睡眠。

  • down_write_trylock:尝试获取写锁,不会等待。成功返回非零值,失败返回 0。

  • up_write:释放写锁,需与 down_write 或成功的 down_write_trylock 成对调用。

  • downgrade_write:将写锁降级为读锁。适用于 “先快速修改数据,后长时间只读访问” 的场景 —— 降级后允许其他读线程进入,提升并发性能。

An rwsem allows either one writer or an unlimited number of readers to hold the semaphore. Writers get priority; as soon as a writer tries to enter the critical section, no readers will be allowed in until all writers have completed their work. This implementation can lead to reader starvation—where readers are denied access for a long time—if you have a large number of writers contending for the semaphore. For this reason, rwsems are best used when write access is required only rarely, and writer access is held for short periods of time.

  • 访问规则:同一时刻,rwsem 要么被一个写线程持有,要么被任意数量的读线程持有(不可同时存在读和写线程)。

  • 写线程优先级:一旦有写线程尝试获取锁,后续读线程会被阻塞,直到所有写线程完成操作并释放锁。

  • 潜在问题:若写线程竞争激烈,可能导致读线程饥饿(长时间无法获取锁)。

rwsem 最适合以下情况:

  • 读操作的频率远高于写操作;

  • 写操作持续时间短,且不频繁。

若写操作频繁或持续时间长,rwsem 的并发优势会消失,甚至因 “写优先级” 导致读线程饥饿,此时不如使用普通信号量(或互斥锁)更高效。

补充说明:

  1. 不可中断睡眠的限制

    down_read 和 down_write 均为不可中断操作,适合内核态中无需响应信号的场景(如中断处理程序之外的同步)。用户态进程若需可中断等待,需自行封装(或避免使用 rwsem)。

  2. 锁降级的注意事项

    downgrade_write 只能将写锁降级为读锁,无法反向升级(读锁不能升级为写锁)。降级后,当前线程仍持有读锁,其他读线程可并发访问,但写线程需等待所有读锁释放。

  3. 与普通信号量的对比

    • 普通信号量:无论读写,均排他访问,实现简单,无饥饿问题;

    • rwsem:读并发、写排他,读多写少场景下性能更优,但实现复杂,可能出现读饥饿。

  4. 现代内核的替代方案

    ​​​​​​​现代内核提供了 struct rw_semaphore 的改进版本(如 struct seqlockstruct rwlock_t),针对不同场景优化了性能和灵活性,可根据实际需求选择。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DeeplyMind

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值