当一个进程睡眠, 它这样做以期望某些条件在以后会成真. 如我们之前注意到的, 任何睡 眠的进程必须在它再次醒来时检查来确保它在等待的条件真正为真. Linux 内核中睡眠的 最简单方式是一个宏定义, 称为 wait_event(有几个变体); 它结合了处理睡眠的细节和 进程在等待的条件的检查. wait_event 的形式是:

wait_event(queue, condition) wait_event_interruptible(queue, condition) wait_event_timeout(queue, condition, timeout) wait_event_interruptible_timeout(queue, condition, timeout)

在所有上面的形式中, queue 是要用的等待队列头. 注意它是"通过值"传递的. 条件是一 个被这个宏在睡眠前后所求值的任意的布尔表达式; 直到条件求值为真值, 进程继续睡眠. 注意条件可能被任意次地求值, 因此它不应当有任何边界效应.

如果你使用 wait_event, 你的进程被置为不可中断地睡眠, 如同我们之前已经提到的, 它常常不是你所要的. 首选的选择是 wait_event_interruptible, 它可能被信号中断. 这个版本返回一个你应当检查的整数值; 一个非零值意味着你的睡眠被某些信号打断, 并 且你的驱动可能应当返回 -ERESTARTSYS. 最后的版本(wait_event_timeout 和 wait_event_interruptible_timeout)等待一段有限的时间; 在这个时间期间(以嘀哒数表 达的, 我们将在第 7 章讨论)超时后, 这个宏返回一个 0 值而不管条件是如何求值的.

图片的另一半, 当然, 是唤醒. 一些其他的执行线程(一个不同的进程, 或者一个中断处 理, 也许)必须为你进行唤醒, 因为你的进程, 当然, 是在睡眠. 基本的唤醒睡眠进程的 函数称为 wake_up. 它有几个形式(但是我们现在只看其中 2 个):

void wake_up(wait_queue_head_t *queue);

void wake_up_interruptible(wait_queue_head_t *queue);

wake_up 唤醒所有的在给定队列上等待的进程(尽管这个情形比那个要复杂一些, 如同我 们之后将见到的). 其他的形式(wake_up_interruptible)限制它自己到处理一个可中断的 睡眠. 通常, 这 2 个是不用区分的(如果你使用可中断的睡眠); 实际上, 惯例是使用 wake_up 如果你在使用 wait_event , wake_up_interruptible 如果你在使用 wait_event_interruptible.

我们现在知道足够多来看一个简单的睡眠和唤醒的例子. 在这个例子代码中, 你可找到一 个称为 sleepy 的模块. 它实现一个有简单行为的设备:任何试图从这个设备读取的进程 都被置为睡眠. 无论何时一个进程写这个设备, 所有的睡眠进程被唤醒. 这个行为由下面 的 read 和 write 方法实现:

static DECLARE_WAIT_QUEUE_HEAD(wq); static int flag = 0;

ssize_t sleepy_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_event_interruptible(wq, flag != 0);

flag = 0;

printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm); return 0; /* EOF */

}

ssize_t sleepy_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);

flag = 1; wake_up_interruptible(&wq);

return count; /* succeed, to avoid retrial */

}

注意这个例子里 flag
变量的使用. 因为
wait_event_interruptible 检查一个必须变为 真的条件, 我们使用 flag 来创建那个条件.

有趣的是考虑当 sleepy_write 被调用时如果有 2 个进程在等待会发生什么. 因为
sleepy_read 重置 flag 为 0 一旦它醒来, 你可能认为醒来的第 2 个进程会立刻回到睡 眠. 在一个单处理器系统, 这几乎一直是发生的事情. 但是重要的是要理解为什么你不能 依赖这个行为.
wake_up_interruptible 调用将使 2 个睡眠进程醒来. 完全可能它们都 注意到 flag 是非零, 在另一个有机会重置它之前. 对于这个小模块, 这个竞争条件是不 重要的. 在一个真实的驱动中, 这种竞争可能导致少见的难于查找的崩溃. 如果正确的操 作要求只能有一个进程看到这个非零值, 它将必须以原子的方式被测试. 我们将见到一个 真正的驱动如何处理这样的情况. 但首先我们必须开始另一个主题.

linux进程简单睡眠的更多相关文章

  1. Linux进程的睡眠和唤醒简析

    COPY FROM:http://www.2cto.com/os/201204/127771.html 1 Linux进程的睡眠和唤醒 在Linux中,仅等待CPU时间的进程称为就绪进程,它们被放置在 ...

  2. Linux进程的睡眠和唤醒

    1   Linux进程的睡眠和唤醒 在Linux中,仅等待CPU时间的进程称为就绪进程,它们被放置在一个运行队列中,一个就绪进程的状态标志位为TASK_RUNNING.一旦一个运行中的进程时间片用完, ...

  3. Linux唤醒抢占----Linux进程的管理与调度(二十三)

    1. 唤醒抢占 当在try_to_wake_up/wake_up_process和wake_up_new_task中唤醒进程时, 内核使用全局check_preempt_curr看看是否进程可以抢占当 ...

  4. Linux守护进程简单介绍和实例具体解释

    Linux守护进程简单介绍和实例具体解释 简单介绍 守护进程(Daemon)是执行在后台的一种特殊进程.它独立于控制终端而且周期性地执行某种任务或等待处理某些发生的事件.守护进程是一种非常实用的进程. ...

  5. Linux内核剖析 之 进程简单介绍

    1.概念 1.1  什么是进程?     进程是程序运行的一个实例.能够看作充分描写叙述程序已经运行到何种程度的数据结构的汇集.     从内核观点看.进程的目的就是担当分配系统资源(CPU时间,内存 ...

  6. linux进程睡眠的介绍

    对于一个进程"睡眠"意味着什么? 当一个进程被置为睡眠, 它被标识为处于一个特殊的状 态并且从调度器的运行队列中去除. 直到发生某些事情改变了那个状态, 这个进程将不被 在任何 C ...

  7. Linux进程操作信息

    Linux进程操作简单小结 linux上进程有5种状态: 1. 运行(正在运行或在运行队列中等待) 2. 中断(休眠中, 受阻, 在等待某个条件的形成或接受到信号) 3. 不可中断(收到信号不唤醒和不 ...

  8. Linux进程实践(1) --Linux进程编程概述

    进程 VS. 程序 什么是程序? 程序是完成特定任务的一系列指令集合. 什么是进程? [1]从用户的角度来看:进程是程序的一次执行过程 [2]从操作系统的核心来看:进程是操作系统分配的内存.CPU时间 ...

  9. 第9章 Linux进程和信号超详细分析

    9.1 进程简单说明 进程是一个非常复杂的概念,涉及的内容也非常非常多.在这一小节所列出内容,已经是我极度简化后的内容了,应该尽可能都理解下来,我觉得这些理论比如何使用命令来查看状态更重要,而且不明白 ...

随机推荐

  1. 什么是PV UV

    PV是网站分析的一个术语,用以衡量网站用户访问的网页的数量.对于广告主,PV值可预期它可以带来多少广告收入.一般来说,PV与来访者的数量成正比,但是PV并不直接决定页面的真实来访者数量,如同一个来访者 ...

  2. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第二十章:阴影贴图

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第二十章:阴影贴图 本章介绍一种在游戏和应用中,模拟动态阴影的基本阴影 ...

  3. POP介绍与使用实践(快速上手动画)

    http://adad184.com/2015/03/11/intro-to-pop/ 前言 动画在APP开发过程中 大家多多少少都会接触到 而且随着ios7的扁平化风格启用之后 越来越多的APP开始 ...

  4. jQuery之父:坚持每天都要写代码

    关于作者:John Resig, jQuery之父,同时也是Pro Javascript Techniques和Secrets of the JavaScript Ninja的作者.他目前主持 Kha ...

  5. laravel 项目本地版本为5.5,线上mysql 为5.7.21版本,执行严格模式

    看到网上很多说修改 但是在mysql 5.7中没有这个参数设置,故放弃: 结合本项目sina_id 10位超过int的最大范围4294967295,所以报错,修改为bigint  即可.

  6. laravel 极验(Geetest) 让验证更安全。

    整理的有些仓促,在9月15号之后会更新更加详细更加全面的文档,供给大家参考,学习! 1.简述 在网站开发中使用频率最高的工具之一便是验证码,验证码在此也是多种多样,不过简单的图片验证码已经可以被机器识 ...

  7. 【JZOJ4832】【NOIP2016提高A组集训第3场10.31】高维宇宙

    题目描述 数据范围 解法 由于大于4的素数只有可能由奇数和偶数的和得出. 所以根据数的奇偶性可以分出两类数奇数和偶数. 奇数之间不会相互匹配,偶数之间也不会相互匹配. 那么原问题转化为二分图最大匹配. ...

  8. Effective C++: 01让自己习惯C++

    01:视C++为一个语言联邦 1:今天的C++已经是个多重范型编程语言(multiparadigm programming language),一个同时支持过程形式(procedural).面向对象形 ...

  9. 实用的cmd命令

    1.打开iis服务器:inetmgr 2.远程连接:mstsc 3.注册表:regedit.exe

  10. phpexcel导出数据库成excel文件

    <?php error_reporting(E_ALL); date_default_timezone_set('Europe/London'); /** PHPExcel */ require ...