当一个进程睡眠, 它这样做以期望某些条件在以后会成真. 如我们之前注意到的, 任何睡 眠的进程必须在它再次醒来时检查来确保它在等待的条件真正为真. 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. .Net Core 认证系统之Cookie认证源码解析

    接着上文.Net Core 认证系统源码解析,Cookie认证算是常用的认证模式,但是目前主流都是前后端分离,有点鸡肋但是,不考虑移动端的站点或者纯管理后台网站可以使用这种认证方式.注意:基于浏览器且 ...

  2. 【python小随笔】List列表的常见函数与切片

    eval()的使用 n = ["2.3","2.56"] m = [] for i in n: k = eval(i) #只是去了最外层的双引号,单引号, 规定 ...

  3. js中的replace问题和textarea回车符问题

    在textarea中输入回车符 在js读取textarea中的值有\r\n然后到业务层转换到string中就有可能变成空格形式然后被存入数据库,当在取出此值的时候则会变成空格的形式,因此我们需要将不显 ...

  4. python 类(class)

  5. Leetcode746.Min Cost Climbing Stairs使用最小花费爬楼梯

    数组的每个索引做为一个阶梯,第 i个阶梯对应着一个非负数的体力花费值 cost[i](索引从0开始). 每当你爬上一个阶梯你都要花费对应的体力花费值,然后你可以选择继续爬一个阶梯或者爬两个阶梯. 您需 ...

  6. 基于GD库的php验证码类(支持中英文字体、背景、干扰点线、扭曲…….)

    转自:http://www.blhere.com/1168.html 12345678910111213141516171819202122232425262728293031323334353637 ...

  7. 谷歌好样的,把 www 也干掉了

    谷歌好样的,把 www 也干掉了 继把 http 干掉后,这次 Chrome 76 连 https 和 www 都一起干掉了. 喜欢简洁,但这个功能演化过程可不简单. 最早觉得把 http 干掉很不方 ...

  8. Vue知识点——vue数据深拷贝方法

    背景 在vue页面传递数据的过程中,传递数据的引用地址并不会改变,所以当我们改变一些数据时,数据源 也会随之改变.可是有很多情景,我们改变传递的数据,并不需要源数据值发生变化,这时我们就需要对数据进行 ...

  9. 如何不让EditText不获得焦点

    http://blog.csdn.net/get123/article/details/9004661

  10. 现代IM系统中的消息系统架构 - 模型篇

    前言 在架构篇中我们介绍了现代IM消息系统的架构,介绍了Timeline的抽象模型以及基于Timeline模型构建的一个支持『消息漫游』.『多端同步』和『消息检索』多种高级功能的消息系统的典型架构.架 ...