linux Completions 机制
内核编程的一个普通模式包括在当前线程之外初始化某个动作, 接着等待这个动作结束. 这个动作可能是创建一个新内核线程或者用户空间进程, 对一个存在着的进程的请求, 或 者一些基于硬件的动作. 在这些情况中, 很有诱惑去使用一个旗标来同步 2 个任务, 使 用这样的代码:
struct semaphore sem; init_MUTEX_LOCKED(&sem); start_external_task(&sem); down(&sem);
外部任务可以接着调用 up(??sem), 在它的工作完成时.
事实证明, 这种情况旗标不是最好的工具. 正常使用中, 试图加锁一个旗标的代码发现旗 标几乎在所有时间都可用; 如果对旗标有很多竞争, 性能会受损并且加锁方案需要重新审 视. 因此旗标已经对"可用"情况做了很多的优化. 当用上面展示的方法来通知任务完成, 然而, 调用 down 的线程将几乎是一直不得不等待; 因此性能将受损. 旗标还可能易于处 于一个( 困难的 ) 竞争情况, 如果它们表明为自动变量以这种方式使用时. 在一些情况 中, 旗标可能在调用 up 的进程用完它之前消失.
这些问题引起了在 2.4.7 内核中增加了 "completion" 接口. completion 是任务使用的 一个轻量级机制: 允许一个线程告诉另一个线程工作已经完成. 为使用 completion, 你 的代码必须包含 <linux/completion.h>. 一个 completion 可被创建, 使用:
DECLARE_COMPLETION(my_completion);
或者, 如果 completion 必须动态创建和初始化: struct completion my_completion; /* ... */
init_completion(&my_completion); 等待 completion 是一个简单事来调用:
void wait_for_completion(struct completion *c);
注意这个函数进行一个不可打断的等待. 如果你的代码调用 wait_for_completion 并且 没有人完成这个任务, 结果会是一个不可杀死的进程.[18]18
另一方面, 真正的 completion 事件可能通过调用下列之一来发出: void complete(struct completion *c);
void complete_all(struct completion *c);
如果多于一个线程在等待同一个 completion 事件, 这 2 个函数做法不同. complete 只 唤醒一个等待的线程, 而 complete_all 允许它们所有都继续. 在大部分情况下, 只有一 个等待者, 这 2 个函数将产生一致的结果.
一个 completion 正常地是一个单发设备; 使用一次就放弃. 然而, 如果采取正确的措施 重新使用 completion 结构是可能的. 如果没有使用 complete_all, 重新使用一个 completion 结构没有任何问题, 只要对于发出什么事件没有模糊. 如果你使用 complete_all, 然而, 你必须在重新使用前重新初始化 completion 结构. 宏定义:
INIT_COMPLETION(struct completion c); 可用来快速进行这个初始化.
作为如何使用 completion 的一个例子, 考虑 complete 模块, 它包含在例子源码里. 这 个模块使用简单的语义定义一个设备: 任何试图从一个设备读的进程将等待(使用 wait_for_completion)直到其他进程向这个设备写. 实现这个行为的代码是:
DECLARE_COMPLETION(comp);
ssize_t complete_read (struct file *filp, char user *buf, size_t count, loff_t *pos)
{
printk(KERN_DEBUG "process %i (%s) going to sleep\n",current->pid, current->comm);
wait_for_completion(&comp);
printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm); return 0; /* EOF */
}
ssize_t complete_write (struct file *filp, const char user *buf, size_t count, loff_t *pos)
在本书编写时, 添加可中断版本的补丁已经流行但是还没有合并到主线中.
printk(KERN_DEBUG
"process %i (%s) awakening the readers...\n", current-
>pid,
current->comm); complete(&comp);
return count; /* succeed, to avoid retrial */
}
有多个进程同时从这个设备"读"是有可能的. 每个对设备的写将确切地使一个读操作完成, 但是没有办法知道会是哪个.
completion 机制的典型使用是在模块退出时与内核线程的终止一起. 在这个原型例子里, 一些驱动的内部工作是通过一个内核线程在一个 while(1) 循环中进行的. 当模块准备好 被清理时, exit 函数告知线程退出并且等待结束. 为此目的, 内核包含一个特殊的函数 给线程使用:
void
complete_and_exit(struct completion *c, long retval);
linux Completions 机制的更多相关文章
- Linux模块机制浅析
Linux模块机制浅析 Linux允许用户通过插入模块,实现干预内核的目的.一直以来,对linux的模块机制都不够清晰,因此本文对内核模块的加载机制进行简单地分析. 模块的Hello World! ...
- android & Linux uevent机制
Linux uevent机制 Uevent是内核通知android有状态变化的一种方法,比如USB线插入.拔出,电池电量变化等等.其本质是内核发送(可以通过socket)一个字符串,应用层(andro ...
- 利用linux信号机制调试段错误(Segment fault)
在实际开发过程中,大家可能会遇到段错误的问题,虽然是个老问题,但是其带来的隐患是极大的,只要出现一次,程序立即崩溃中止.如果程序运行在PC中,segment fault的调试相对比较方便,因为可以通过 ...
- Linux 内存机制详解宝典
Linux 内存机制详解宝典 在linux的内存分配机制中,优先使用物理内存,当物理内存还有空闲时(还够用),不会释放其占用内存,就算占用内存的程序已经被关闭了,该程序所占用的内存用来做缓存使用,对于 ...
- Linux Namespaces机制——实现
转自:http://www.cnblogs.com/lisperl/archive/2012/05/03/2480573.html 由于Linux内核提供了PID,IPC,NS等多个Namespace ...
- Linux Namespaces机制
转自:http://www.cnblogs.com/lisperl/archive/2012/05/03/2480316.html Linux Namespaces机制提供一种资源隔离方案.PID,I ...
- Linux分页机制之概述--Linux内存管理(六)
1 分页机制 在虚拟内存中,页表是个映射表的概念, 即从进程能理解的线性地址(linear address)映射到存储器上的物理地址(phisical address). 很显然,这个页表是需要常驻内 ...
- [转帖]Linux分页机制之分页机制的演变--Linux内存管理(七)
Linux分页机制之分页机制的演变--Linux内存管理(七) 2016年09月01日 20:01:31 JeanCheng 阅读数:4543 https://blog.csdn.net/gatiem ...
- [转帖]Linux分页机制之概述--Linux内存管理(六)
Linux分页机制之概述--Linux内存管理(六) 2016年09月01日 19:46:08 JeanCheng 阅读数:5491 标签: linuxkernel内存管理分页架构更多 个人分类: ┈ ...
随机推荐
- 深入浅出Cocoa之消息【转】
在入门级别的ObjC 教程中,我们常对从C++或Java 或其他面向对象语言转过来的程序员说,ObjC 中的方法调用(ObjC中的术语为消息)跟其他语言中的方法调用差不多,只是形式有些不同而已. 譬如 ...
- 【JZOJ3873】【NOIP2014八校联考第4场第2试10.20】乐曲创作(music)
ujfuiaty 小可可是音乐学院的一名学生,他需要经常创作乐曲完成老师布置的作业. 可是,小可可是一个懒惰的学生.所以,每次完成作业时,他不会重新创作一首新的乐曲,而是去修改上一次创作过的乐曲作为作 ...
- Directx11教程(55) 建立球形和锥形物体
原文:Directx11教程(55) 建立球形和锥形物体 本教程中,我们新建2个model class,SphereModelClass以及CylinderModelClass,分别用来表示球形和锥形 ...
- 为什么要Code Review
刚才专注看了下zwchen的博客,读到Code Reivew这一篇,觉得自己也了说话的冲动. 我们Team实施Code Reivew近5年,到今天,我们的结论是: Code Review是我们项目成功 ...
- mogodb 修改字段属性
修改为decimal类型 db.shopgoods.find({'Pricing.Detail':{$type:2}}).forEach(function(x){x.Pricing.Detail=Nu ...
- UVA_10071:Back to High School Physics
Language:C++ 4.8.2 #include<stdio.h> int main(void) { int v, t; while(scanf("%d%d", ...
- 实用的cmd命令
1.打开iis服务器:inetmgr 2.远程连接:mstsc 3.注册表:regedit.exe
- UVa 10502【dp】
uva 10502 题意:给定01矩阵,求有多少个由1构成的矩阵.1本事也算一个矩阵. 到最后还是想不出来..... 每次枚举两行,从第i行到第j行,k枚举矩阵的宽(column).这样就相当于每次看 ...
- oralce函数 STDDEV([distinct|all]x)
[功能]统计数据表选中行x列的标准误差. [参数]all表示对所有的值求标准误差,distinct只对不同的值求标准误差,默认为all 如果有参数distinct或all,需有空格与x(列)隔开. [ ...
- oralcle函数 AVG([distinct|all]x)
[功能]统计数据表选中行x列的平均值. [参数]all表示对所有的值求平均值,distinct只对不同的值求平均值,默认为all 如果有参数distinct或all,需有空格与x(列)隔开. [参数] ...