内核编程的一个普通模式包括在当前线程之外初始化某个动作, 接着等待这个动作结束. 这个动作可能是创建一个新内核线程或者用户空间进程, 对一个存在着的进程的请求, 或 者一些基于硬件的动作. 在这些情况中, 很有诱惑去使用一个旗标来同步 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 机制的更多相关文章

  1. Linux模块机制浅析

    Linux模块机制浅析   Linux允许用户通过插入模块,实现干预内核的目的.一直以来,对linux的模块机制都不够清晰,因此本文对内核模块的加载机制进行简单地分析. 模块的Hello World! ...

  2. android & Linux uevent机制

    Linux uevent机制 Uevent是内核通知android有状态变化的一种方法,比如USB线插入.拔出,电池电量变化等等.其本质是内核发送(可以通过socket)一个字符串,应用层(andro ...

  3. 利用linux信号机制调试段错误(Segment fault)

    在实际开发过程中,大家可能会遇到段错误的问题,虽然是个老问题,但是其带来的隐患是极大的,只要出现一次,程序立即崩溃中止.如果程序运行在PC中,segment fault的调试相对比较方便,因为可以通过 ...

  4. Linux 内存机制详解宝典

    Linux 内存机制详解宝典 在linux的内存分配机制中,优先使用物理内存,当物理内存还有空闲时(还够用),不会释放其占用内存,就算占用内存的程序已经被关闭了,该程序所占用的内存用来做缓存使用,对于 ...

  5. Linux Namespaces机制——实现

    转自:http://www.cnblogs.com/lisperl/archive/2012/05/03/2480573.html 由于Linux内核提供了PID,IPC,NS等多个Namespace ...

  6. Linux Namespaces机制

    转自:http://www.cnblogs.com/lisperl/archive/2012/05/03/2480316.html Linux Namespaces机制提供一种资源隔离方案.PID,I ...

  7. Linux分页机制之概述--Linux内存管理(六)

    1 分页机制 在虚拟内存中,页表是个映射表的概念, 即从进程能理解的线性地址(linear address)映射到存储器上的物理地址(phisical address). 很显然,这个页表是需要常驻内 ...

  8. [转帖]Linux分页机制之分页机制的演变--Linux内存管理(七)

    Linux分页机制之分页机制的演变--Linux内存管理(七) 2016年09月01日 20:01:31 JeanCheng 阅读数:4543 https://blog.csdn.net/gatiem ...

  9. [转帖]Linux分页机制之概述--Linux内存管理(六)

    Linux分页机制之概述--Linux内存管理(六) 2016年09月01日 19:46:08 JeanCheng 阅读数:5491 标签: linuxkernel内存管理分页架构更多 个人分类: ┈ ...

随机推荐

  1. WinForm 实现主程序(exe)与其关联类库(*.dll)分开存放

    WinForm 实现主程序(exe)与其关联类库(*.dll)分开存放    开发环境:   Microsoft Windows 7 SP1 Microsoft.NET Framework 4.0 ( ...

  2. python中的open函数

    open函数用于文件处理 操作文件时,一般需要经历如下步骤: 打开文件 操作文件 一.打开文件 1 文件句柄 = open('文件路径', '模式') 打开文件时,需要指定文件路径和以何等方式打开文件 ...

  3. 【JZOJ4791】【NOIP2016提高A组模拟9.21】矩阵

    题目描述 在麦克雷的面前出现了一个有n*m个格子的矩阵,每个格子用"."或"#"表示,"."表示这个格子可以放东西,"#" ...

  4. 第一章 Web应用程序开发基础

    一.HTTP协议工作机制 HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传送协议.它是一种主流B/S架构中应用的通信 ...

  5. 2018-11-30-WPF-解决-ListView-的滚动条不显示

    title author date CreateTime categories WPF 解决 ListView 的滚动条不显示 lindexi 2018-11-30 19:24:57 +0800 20 ...

  6. Ui自动化测试框架

    为了提高我们的UI测试效率,我们引用Ui自动化测试框架,这里简单先描述一下,后续会详细补充: 了解一个测试框架,我们就需要了解一下源码,能看懂源码即可: 1.稳定先封装wait EC,电脑性能配置较好 ...

  7. Servlet FilterConfig

    FilterConfig的对象由Web容器创建.这个对象可用于获取web.xml文件中Filter的配置信息 文件:index.html <!DOCTYPE html> <html& ...

  8. 两种获取python版本的方法

    方法1:查看python版本 import sys print("当前python版本",sys.version) 方法2:cmd框中查看的两种方式

  9. java执行sql语句使用别名时显示Column '***' not found

    java执行sql语句使用别名时显示Column '*' not found 在做一个小项目时遇到个问题,执行sql语句使用别名时总是报sql异常 Column '*' not found,折腾半天终 ...

  10. mySQL start service失败终极解决办法

    start service失败  原因是电脑没删干净.具体1.先卸载2.计算机“搜索”所有MySQL文件  注意隐藏文件也可以搜索出来全部删除.3.清除注册表MySQL及子项.4.防火墙的问题 不要勾 ...