linux进程简单睡眠
当一个进程睡眠, 它这样做以期望某些条件在以后会成真. 如我们之前注意到的, 任何睡 眠的进程必须在它再次醒来时检查来确保它在等待的条件真正为真. 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进程简单睡眠的更多相关文章
- Linux进程的睡眠和唤醒简析
COPY FROM:http://www.2cto.com/os/201204/127771.html 1 Linux进程的睡眠和唤醒 在Linux中,仅等待CPU时间的进程称为就绪进程,它们被放置在 ...
- Linux进程的睡眠和唤醒
1 Linux进程的睡眠和唤醒 在Linux中,仅等待CPU时间的进程称为就绪进程,它们被放置在一个运行队列中,一个就绪进程的状态标志位为TASK_RUNNING.一旦一个运行中的进程时间片用完, ...
- Linux唤醒抢占----Linux进程的管理与调度(二十三)
1. 唤醒抢占 当在try_to_wake_up/wake_up_process和wake_up_new_task中唤醒进程时, 内核使用全局check_preempt_curr看看是否进程可以抢占当 ...
- Linux守护进程简单介绍和实例具体解释
Linux守护进程简单介绍和实例具体解释 简单介绍 守护进程(Daemon)是执行在后台的一种特殊进程.它独立于控制终端而且周期性地执行某种任务或等待处理某些发生的事件.守护进程是一种非常实用的进程. ...
- Linux内核剖析 之 进程简单介绍
1.概念 1.1 什么是进程? 进程是程序运行的一个实例.能够看作充分描写叙述程序已经运行到何种程度的数据结构的汇集. 从内核观点看.进程的目的就是担当分配系统资源(CPU时间,内存 ...
- linux进程睡眠的介绍
对于一个进程"睡眠"意味着什么? 当一个进程被置为睡眠, 它被标识为处于一个特殊的状 态并且从调度器的运行队列中去除. 直到发生某些事情改变了那个状态, 这个进程将不被 在任何 C ...
- Linux进程操作信息
Linux进程操作简单小结 linux上进程有5种状态: 1. 运行(正在运行或在运行队列中等待) 2. 中断(休眠中, 受阻, 在等待某个条件的形成或接受到信号) 3. 不可中断(收到信号不唤醒和不 ...
- Linux进程实践(1) --Linux进程编程概述
进程 VS. 程序 什么是程序? 程序是完成特定任务的一系列指令集合. 什么是进程? [1]从用户的角度来看:进程是程序的一次执行过程 [2]从操作系统的核心来看:进程是操作系统分配的内存.CPU时间 ...
- 第9章 Linux进程和信号超详细分析
9.1 进程简单说明 进程是一个非常复杂的概念,涉及的内容也非常非常多.在这一小节所列出内容,已经是我极度简化后的内容了,应该尽可能都理解下来,我觉得这些理论比如何使用命令来查看状态更重要,而且不明白 ...
随机推荐
- JavaEE架构简介与JavaWeb新特性
Fragment 将一个web应用做成几个部分,然后整合 创建Fragment项目 然后打包放入Servlet项目中的WEB-INF下的lib中 注解 @WebServlet @WebServle ...
- 几种常见的flex布局
1,水平等距排列.俩端对齐.垂直方向居顶对齐 html: <div class="container flex"> <div class="div1&q ...
- IO流理解方式小结
从业以来一直对IO不甚了解,每次看到都头疼不已,最近有时间小小的总结一下,下面以FileIO流为]; //文件输入流 FileInputStream in = new FileInputStream( ...
- DAY1-作业
Python-day1-------> 本节内容: Python介绍 发展史 Python 2 or 3? 安装 Hello World程序 变量 用户输入 模块初识 .pyc是个什么鬼? 数据 ...
- 2019.10.24TCP协程处理
server from gevent import monkey,spawn monkey.patch_all() import socket server = socket.socket() ser ...
- 2019-10-31-C#-强转空会不会出现异常
title author date CreateTime categories C# 强转空会不会出现异常 lindexi 2019-10-31 8:53:6 +0800 2019-9-10 11:4 ...
- ACK容器服务虚拟节点使用阿里云日志服务来收集业务容器日志
按照这篇博文的介绍,可以在ACK集群上通过Helm的方式部署虚拟节点,提升集群的弹性能力.现在,通过虚拟节点部署的ECI弹性容器实例也支持将stdout输出.日志文件同步到阿里云日志服务(SLS)进行 ...
- python系列之(3)爬取豆瓣图书数据
上次介绍了beautifulsoup的使用,那就来进行运用下吧.本篇将主要介绍通过爬取豆瓣图书的信息,存储到sqlite数据库进行分析. 1.sqlite SQLite是一个进程内的库,实现了自给自足 ...
- 【C++】为什么INT_MIN不是直接写成-2147483648(转载)
最近在编程中遇到一个问题: #include <iostream> using namespace std; int main() { int n = -2147483648; //cou ...
- 集合--Collection接口详解&&迭代器
/* * 集合的顶层接口--Collection接口 * 添加 * add() * addAll() * * 遍历集合 * iterator() 迭代器 * * 删除 * remove() * rem ...