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 进程简单说明 进程是一个非常复杂的概念,涉及的内容也非常非常多.在这一小节所列出内容,已经是我极度简化后的内容了,应该尽可能都理解下来,我觉得这些理论比如何使用命令来查看状态更重要,而且不明白 ...
随机推荐
- web框架起源
web框架 python三大主流web框架 django 大而全,自带的组件和功能极多, 缺点:写小项目时候会比较笨重(杀鸡用牛刀),大并发不行,3000撑死 flask 小而精 自带的组件和功能极少 ...
- 微服务开源生态报告 No.5
「微服务开源生态报告」,汇集各个开源项目近期的社区动态,帮助开发者们更高效的了解到各开源项目的最新进展. 社区动态包括,但不限于:版本发布.人员动态.项目动态和规划.培训和活动. 非常欢迎国内其他微服 ...
- 小爬爬5:重点回顾&&移动端数据爬取1
1. ()什么是selenium - 基于浏览器自动化的一个模块 ()在爬虫中为什么使用selenium及其和爬虫之间的关联 - 可以便捷的获取动态加载的数据 - 实现模拟登陆 ()列举常见的sele ...
- Python学习之路10☞面向对象进阶
一 isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 1 class Foo(objec ...
- 洛谷2387 BZOJ3669魔法森林题解
题目链接 BZ链接 这道题被很多人用spfa水了过去,表示很... 其实spfa很好卡,这组数据可以卡掉大多数spfa 链接:密码:rjvk 这里讲一下LCT的做法 我们按照a将边排序,然后依次添加 ...
- 64位linux源码安装mysql
一:下载mysql http://dev.mysql.com/downloads/mysql/中的Generally Available(GA) Releases标签页,在MySQL Communit ...
- c++第四次作业:继承
继承与派生 基本概念和语法 概念 继承与派生是同一过程从不同角度看 保持已有的特性而构造新类的过程称为继承. 在已有类的基础上新增自己的特性而产生新类的过程为派生. 被继承的已有类称为基类(父类) 派 ...
- 关于取List中的指定几条数据以及注意事项
list1 = list2.subList(start, end); start,end分别是第几个到第几个. 注意的是此方法和substring一样,包含前不包含结尾,取下标索引 另一个注意的地方是 ...
- 00docker安装和简介
Docker是用于开发.装载和运行应用的开放平台.Docker项目的目标是实现轻量的操作系统级虚拟化解决方案,它提供了一种在容器中安全隔离地运行应用程序的方式.可以在宿主机上运行多个容器. Docke ...
- GMTC2019|闲鱼-基于Flutter的架构演进与创新
2012年应届毕业加入阿里巴巴,主导了闲鱼基于Flutter的新混合架构,同时推进了Flutter在闲鱼各业务线的落地.未来将持续关注终端技术的演变及趋势 Flutter的优势与挑战 Flutter是 ...