Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7556265
  • 博文数量: 961
  • 博客积分: 15795
  • 博客等级: 上将
  • 技术积分: 16612
  • 用 户 组: 普通用户
  • 注册时间: 2010-08-07 14:23
文章分类

全部博文(961)

文章存档

2016年(1)

2015年(61)

2014年(41)

2013年(51)

2012年(235)

2011年(391)

2010年(181)

分类: LINUX

2012-07-25 11:00:12

自旋锁概念上简单. 一个自旋锁是一个互斥设备, 只能有 2 个值:"上锁""解锁". 它常常实现为一个整数值中的一个单个位. 想获取一个特殊锁的代码测试相关的位. 如果锁是可用的, 这个"上锁"位被置位并且代码继续进入临界区. 相反, 如果这个锁已经被别人获得, 代码进入一个紧凑的循环中反复检查这个锁, 直到它变为可用. 这个循环就是自旋锁的"自旋"部分.

自旋锁 API 简介

自旋锁原语要求的包含文件是 . 一个实际的锁有类型 spinlock_t. 象任何其他数据结构, 一个 自旋锁必须初始化. 这个初始化可以在编译时完成, 如下:

spinlock_t my_lock = SPIN_LOCK_UNLOCKED;

或者在运行时使用:

void spin_lock_init(spinlock_t *lock);

在进入一个临界区前, 你的代码必须获得需要的 lock , :

void spin_lock(spinlock_t *lock);

注意所有的自旋锁等待是, 由于它们的特性, 不可中断的. 一旦你调用 spin_lock, 你将自旋直到锁变为可用.

为释放一个你已获得的锁, 传递它给:

void spin_unlock(spinlock_t *lock);

 

其他参考内容:

自旋锁函数

我们已经看到 2 个函数, spin_lock spin_unlock, 可以操作自旋锁. 有其他几个函数, 然而, 有类似的名子和用途. 我们现在会展示全套. 这个讨论将带我们到一个我们无法在几章内适当涵盖的地方; 自旋锁 API 的完整理解需要对中断处理和相关概念的理解.

实际上有 4 个函数可以加锁一个自旋锁:

void spin_lock(spinlock_t *lock);

void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);

void spin_lock_irq(spinlock_t *lock);

void spin_lock_bh(spinlock_t *lock)

我们已经看到自旋锁如何工作. spin_loc_irqsave 禁止中断(只在本地处理器)在获得自旋锁之前; 之前的中断状态保存在 flags . 如果你绝对确定在你的处理器上没有禁止中断的(或者, 换句话说, 你确信你应当在你释放你的自旋锁时打开中断), 你可以使用 spin_lock_irq 代替, 并且不必保持跟踪 flags. 最后, spin_lock_bh 在获取锁之前禁止软件中断, 但是硬件中断留作打开的.

如果你有一个可能被在(硬件或软件)中断上下文运行的代码获得的自旋锁, 你必须使用一种 spin_lock 形式来禁止中断. 其他做法可能死锁系统, 迟早. 如果你不在硬件中断处理里存取你的锁, 但是你通过软件中断(例如, 在一个 tasklet 运行的代码, 在第 7 章涉及的主题 ), 你可以使用 spin_lock_bh 来安全地避免死锁, 而仍然允许硬件中断被服务.

也有 4 个方法来释放一个自旋锁; 你用的那个必须对应你用来获取锁的函数.

void spin_unlock(spinlock_t *lock);

void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);

void spin_unlock_irq(spinlock_t *lock);

void spin_unlock_bh(spinlock_t *lock);

每个 spin_unlock 变体恢复由对应的 spin_lock 函数锁做的工作. 传递给 spin_unlock_irqrestore flags 参数必须是传递给 spin_lock_irqsave 的同一个变量. 你必须也调用 spin_lock_irqsave spin_unlock_irqrestore 在同一个函数里. 否则, 你的代码可能破坏某些体系.

还有一套非阻塞的自旋锁操作:

int spin_trylock(spinlock_t *lock);

int spin_trylock_bh(spinlock_t *lock);

这些函数成功时返回非零( 获得了锁 ), 否则 0. 没有"try"版本来禁止中断.

读者/写者自旋锁

内核提供了一个自旋锁的读者/写者形式, 直接模仿我们在本章前面见到的读者/写者旗标. 这些锁允许任何数目的读者同时进入临界区, 但是写者必须是排他的存取. 读者写者锁有一个类型 rwlock_t, 中定义. 它们可以以 2 种方式被声明和被初始化:

rwlock_t my_rwlock = RW_LOCK_UNLOCKED; /* Static way */

rwlock_t my_rwlock;

rwlock_init(&my_rwlock); /* Dynamic way */

可用函数的列表现在应当看来相当类似. 对于读者, 下列函数是可用的:

void read_lock(rwlock_t *lock);

void read_lock_irqsave(rwlock_t *lock, unsigned long flags);

void read_lock_irq(rwlock_t *lock);

void read_lock_bh(rwlock_t *lock);

 

void read_unlock(rwlock_t *lock);

void read_unlock_irqrestore(rwlock_t *lock, unsigned long flags);

void read_unlock_irq(rwlock_t *lock);

void read_unlock_bh(rwlock_t *lock);

有趣地, 没有 read_trylock. 对于写存取的函数是类似的:

void write_lock(rwlock_t *lock);

void write_lock_irqsave(rwlock_t *lock, unsigned long flags);

void write_lock_irq(rwlock_t *lock);

void write_lock_bh(rwlock_t *lock);

int write_trylock(rwlock_t *lock);

 

void write_unlock(rwlock_t *lock);

void write_unlock_irqrestore(rwlock_t *lock, unsigned long flags);

void write_unlock_irq(rwlock_t *lock);

void write_unlock_bh(rwlock_t *lock);

读者/写者锁能够饿坏读者, 就像 rwsem 一样.

 

阅读(2130) | 评论(0) | 转发(4) |
给主人留下些什么吧!~~