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

    题目链接 判断一颗二叉树是否是二叉搜索树(二叉排序树),也就是BST 如果该二叉树是BST, 那么对其中序遍历,所得序列一定是单调递增的(不考虑有重复数值的情况) 附上代码: /** * Defini ...

  2. bash 小技巧

    CTRL-R (reverse find),按下之后敲几个字母就能在最近打过的命令里搜索.

  3. Servlet各种接口和类

    http://blog.csdn.net/jediael_lu/article/details/25036019

  4. 【JZOJ4812】【NOIP2016提高A组五校联考2】string

    题目描述 给出一个长度为n, 由小写英文字母组成的字符串S, 求在所有由小写英文字母组成且长度为n 且恰好有k 位与S 不同的字符串中,给定字符串T 按照字典序排在第几位. 由于答案可能很大,模10^ ...

  5. 【JZOJ4772】【NOIP2016提高A组模拟9.9】运输妹子

    题目描述 小轩轩是一位非同一般的的大农(lao)场(si)主(ji),他有一大片非同一般的农田,并且坐落在一条公路旁(可以认为是数轴),在他的农田里种的东西也非同一般--不是什么水稻小麦,而是妹子. ...

  6. CF789D Mike and distribution

    题目连接 一道人类智慧题.... 这道题目可以转化为在a,b中的选出一些位置,使得这些位置处的值加起来大于没有选的位置的值 我们按照a的权值排序,选择第一个元素,其与元素两两分组,每组选择b更大的那一 ...

  7. 微信小程序组件——bindtap和catchtap的区别

    了解知识点 DOM模型是一个树形结构,在DOM模型中,HTML元素是有层次的.当一个HTML元素上产生一个事件时,该事件会在DOM树中元素节点与根节点之间按特定的顺序传播,路径所经过的节点都会收到该事 ...

  8. el-dialog 一些问题 局中滚动

    .el-dialog { position: absolute; top: 50%; left: 50%; margin: 0 !important; transform: translate(-50 ...

  9. LeetCode108 Convert Sorted Array to Binary Search Tree

    Given an array where elements are sorted in ascending order, convert it to a height balanced BST. (M ...

  10. Android 整合实现简单易用、功能强大的RecyclerView

    之前总是会有人在一些开发群里问,有木有比较好使且功能强大些的RecyclerVew,比如支持下来刷新,加载更多等,还有人在问,如何为RecyclerView添加分割线,尤其是如何为网格布局添加分割线? ...