信号量与自旋锁(4): 其他信号量

1. 读取/写入信号量
信号量对所有调用者执行互斥操作, 而不管线程想做什么(读/写). 正如这样, 我们可以把任务划分为两种类型: 读取和写入. 多个并发的读取应该是被允许的, 因为只读任务可并行完成他们的工作, 这样做可以大大提高性能.

如此, 便有了Linux内核提供的一种特殊信号量类型, 称为"rwsem"(reader/writer semaphore). 虽然在驱动程序中使用rwsem的机会相对比较少, 但偶尔也比较有用.

头文件: <linux/rwsem.h>
数据类型: struct rw_semaphore

一个rwsem对象必须用一下函数显式地初始化:
void init_rwsem(struct rw_semaphore *sem);

对受保护资源的只读访问, 可和其他读取者并发地访问. 可用的接口有:
/* 可能会将调用进程置于不可中断的休眠 */
void down_read(struct rw_semaphore *sem);
/* 可中断版本
 * 授予访问时返回非0, 其他情况返回0 */
int down_read_trylock(struct rw_semaphore *sem);
/* 释放rw_sem对象 */
void up_read(struct rw_semaphore *sem);


针对写入者的接口类似于读取者:
void down_write(struct rw_semaphore *sem);
int down_write_trylock(struct rw_semaphore *sem);
void up_write(struct rw_semaphore *sem);

这3个函数与读取者的对应函数行为相同, 他们提供的是写入访问.

/* 当某个快速改变获得写入者锁,
 *其后有更长时间的只读访问的时候,
 *我们可以调用该函数来允许其他读取者访问 */
void downgrade_write(struct rw_semaphore *sem);


读取/写入信号量特点:
  • 一个rwsem可以允许一个写入者或无限多个读取者拥有该信号量.
  • 写入者具有更高的优先级, 某个写入者试图进入临界区, 在其完成工作之前, 不会允许读取者获得访问.
  • 如果大量写入者竞争该信号量, 会导致读取者"饿死".
  • 最好在很少需要写访问且写入者只会短期拥有信号量什使用rwsem.

2. Completion
有时, 由于信号量轻松up操作之后, 会产生过长时间的操作, 为了避免信号量执行down操作导致的长时间阻塞, 内核提供了一组completion(完成)接口解决这种问题.

Completion是一种轻量级的机制, 它允许一个线程告诉另一个线程某个工作已经完成.

头文件: <linux/completion.h>
数据类型: struct completion

一个completion对象可以通过两种方法创建和初始化:
DECLARE_COMPLETION(my_completion);

或者, 如果必须动态, 则使用:
struct completion my_completion;
...
...
init_completion(&my_completion);


对completion操作的接口有:
等待completion的操作可以用:
/* 执行一个非中断等待 */
void wait_for_completion(struct completion *c);


实际的completion事件调用可以用:
/* 只会唤醒一个等待线程 */
void complete(struct completion *c);

/* 唤醒所有等待线程 */
void complete_all(struct completion *c);


但在大多数情况下, 只会有一个等待者, 此时两个函数效果相同.

Completion的特点:
  • 一个completion通常是一个单次设备, 它只会被使用一次然后被丢弃.
  • 触发事件明确时, 如果没有使用complete_all, 可以重复使用一个completion结构.
  • 如果使用了complete_all, 则必须在重复使用该结构之前重新初始化它:
  • 可以用INIT_COMPLETION(struct completion *c);进行初始化

Completion机制的典型是模块退出时的内核线程终止. 这时, 驱动程序内部由一个while(1)循环完成, 当内核准备清楚该模块时, exit函数会令线程退出并等待completion. 此时, 内核可调用一个特殊函数:
void complete_and_exit(struct completion *c, long retval);
/* 其中retval是exit的返回值, 可用于错误代码检查 */
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值