- 1、本文档共5页,可阅读全部内容。
- 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
5.3. 旗标和互斥体
5.3. 旗标和互斥体
让我们看看我们如何给 scull 加锁. 我们的⽬标是使我们对 scull 数据结构的操作原⼦
化, 就是在有其他执⾏ 程的情况下这个操作⼀次发⽣. 对于我们的内存泄漏例⼦, 我
们需要保证, 如果⼀个 程发现必须分配⼀个特殊的内存块, 它有机会进⾏这个分配在
其他 程可做测试之前. 为此, 我们必须建⽴临界区: 在任何给定时间只有⼀个 程可
以执⾏的代码.
不是所有的临界区是同样的, 因此内核提供了不同的原语适⽤不同的需求. 在这个例⼦
中, 每个对 scull 数据结构的存取都发⽣在由⼀个直接⽤户请求所产⽣的进程上下⽂中;
没有从中断处理或者其他异步上下⽂中的存取. 没有特别的周期(响应时间)要求; 应⽤
程序程序员理解 I/O 请求常常不是马上就满⾜的. 进⼀步讲, scull 没有持有任何其他关
键系统资源, 在它存取它⾃⼰的数据结构时. 所有这些意味着如果 scull 驱动在等待轮
到它存取数据结构时进⼊睡眠, 没⼈介意.
去睡眠 在这个上下⽂中是⼀个明确定义的术语. 当⼀个 Linux 进程到了⼀个它⽆法
做进⼀步处理的地⽅时, 它去睡眠(或者 阻塞), 让出处理器给别⼈直到以后某个时间
它能够再做事情. 进程常常在等待 I/O 完成时睡眠. 随着我们深⼊内核, 我们会遇到很多
情况我们不能睡眠. 然⽽ scull 中的 write ⽅法不是其中⼀个情况. 因此我们可使⽤⼀个
加锁机制使进程在等待存取临界区时睡眠.
正如重要地, 我们将进⾏⼀个可能会睡眠的操作( 使⽤ kmalloc 分配内存 ) -- 因此睡眠
是⼀个在任何情况下的可能性. 如果我们的临界区要正确⼯作, 我们必须使⽤⼀个加锁
原语在⼀个拥有锁的进程睡眠时起作⽤. 不是所有的加锁机制都能够在可能睡眠的地
⽅使⽤( 我们在本章后⾯会看到⼏个不可以的 ) . 然⽽, 对我们现在的需要, 最适合的机
制时⼀个旗标.
旗标在计算机科学中是⼀个被很好理解的概念. 在它的核⼼, ⼀个旗标是⼀个单个整型
值, 结合有⼀对函数, 典型地称为 P 和 V . ⼀个想进⼊临界区的进程将在相关旗标上调
⽤ P; 如果旗标的值⼤于零, 这个值递减 1 并且进程继续. 相反, 如果旗标的值是 ( 或
更⼩ ), 进程必须等待直到别⼈释放旗标. 解锁⼀个旗标通过调⽤ V 完成; 这个函数递增
旗标的值, 并且, 如果需要, 唤醒等待的进程.
当旗标⽤作互斥 -- 阻⽌多个进程同时在同⼀个临界区内运⾏ -- 它们的值将初始化为 1.
这样的旗标在任何给定时间只能由⼀个单个进程或者 程持有. 以这种模式使⽤的旗
标有时称为⼀个互斥锁, 就是, 当然, 互斥的缩写. ⼏乎所有在 Linux 内核中发现的旗
标都是⽤作互斥.
5.3.1. Linux 旗标实现
Linux 内核提供了⼀个遵守上⾯语义的旗标实现, 尽管术语有些不同. 为使⽤旗标, 内核
代码必须包含 asm/semaphore .h . 相关的类型是 struct semaphore; 实际旗标可以⽤⼏
种⽅法来声明和初始化. ⼀种是直接创建⼀个旗标, 接着使⽤ sema_init 来设定它:
void sema_init(struct semaphore *sem, int val);
这⾥ val 是安排给旗标的初始值.
然⽽, 通常旗标以互斥锁的模式使⽤. 为使这个通⽤的例⼦更容易些, 内核提供了⼀套
帮助函数和宏定义. 因此, ⼀个互斥锁可以声明和初始化, 使⽤下⾯的⼀种:
DECLARE_MU EX(name);
DECLARE_MU EX_LOCKED(name);
这⾥, 结果是⼀个旗标变量( 称为 name ), 初始化为 1 ( 使⽤ DECLARE_MUTEX ) 或者
(使⽤ DECLARE_MUTEX_LOCKED ) . 在后⼀种情况, 互斥锁开始于上锁的状态; 在
允许任何 程存取之前将不得不显式解锁它.
如果互斥锁必须在运⾏时间初始化( 这是如果动态分配它的情况, 举例来说), 使⽤下列
中的⼀个:
void init_MU EX(struct semaphore *sem);
void init_MU EX_LOCKED(struct semaphore *sem);
在 Linux 世界中, P 函数称为 down -- 或者这个名⼦的某个变体. 这⾥, down 指的是这
样的
文档评论(0)