Linux 内核睡眠的几种方式
译至:http://geeki.wordpress.com/2010/10/30/ways-of-sleeping-in-linux-kernel/
在Linux中睡眠有2-3种不同的方法。
睡眠的第一种简单的方法是将当前进程的状态设置为INTERRUPTIBLE或NON_INTERRUPTIBLE然后调用schedule。将进程设置为RUNNING之外状态很重要,因为只有这样,内核会将进程移出运行队列。进程被调度出去后,它需要以某种方式被调度回来 - 用wake_up()来实现。 这需要进程的task_struct中作为参数。 下面是一段来自Linux Journal的示例代码段:
[cpp] view plaincopy
- //Process A:
- spin_lock(&list_lock);
- if(list_empty(&list_head)) {
- spin_unlock(&list_lock);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- spin_lock(&list_lock);
- }
- /* Rest of the code ... */
- spin_unlock(&list_lock);
- //Process B:
- spin_lock(&list_lock);
- list_add_tail(&list_head, new_node);
- spin_unlock(&list_lock);
- wake_up_process(processA_task);
上面的一段代码会导致一个“无效唤醒”的竞争条件问题。 说明如下:该进程对一些条件检查,然后设置任务状态为可中断并进入睡眠。 这时可能有一个小的竞争条件,当满足该条件的进程在条件检查之后唤醒睡眠进程时(唤醒任务仅仅是将任务状态设置成RUNNING,并将它保持在运行队列) - 这会导致一种情况:睡眠进程在唤醒进程将其唤醒后进入睡眠 - 这就是无效唤醒的问题。 这样做的后果可能会很严重也可能并不严重。 如果睡眠进程将条件标记为假,然后继续睡眠,那么这个无效唤醒的问题将导致睡眠进程永远保持该状态。 但是,如果条件是通过外部满足的话,那么最终条件将变为真,唤醒进程将唤醒睡眠进程。 这种情况的解决方法是在检查前设置任务状态 - 因此,如果这个进程进入睡眠状态,那么它将保持在运行队列而不是等待队列。 如果任务状态是running的话,schedule() API将保持进程只在运行队列。
还有一个问题,这种形式的睡眠要求waker进程中必须知道睡眠进程的task_struct。当存在一个以上的睡眠进程时这可能令人厌倦。 因此,在内核中睡眠的另一种形式是使用等待队列。 下面是一个示例一段代码,声明了一个等待队列,并把自己保持在等待队列。
[cpp] view plaincopy
- DECLARE_WAIT_QUEUE_HEAD(my_event);
- wait_event_interruptible(my_event, (cond == x));
- void my_wake_up(void)
- {
- if (cond == x)
- return;
- set_bit(2, &my_flags);
- wake_up_interruptible(&my_event);
- }
正如在上面这段代码中可以看出,当我们在一个队列中等待时,我们也传递了一个条件用于检查 - 这样内核在将进程保持在等待队列之前要确保这个条件不为真。内核将改变进程的状态,然后检查条件,并把该进程中加入等待队列。 当时间到时,waker进程将来唤醒等待队列上进程 - 这样,它不需要知道哪些进程正在睡眠,它只需知道等待队列。 在一定程度上比之前的不可扩展的睡眠形式更好。 还有一个API,wake_up_all(),将唤醒所有的进程 - 这个API如果不能正确使用会导致惊群问题。 不过,也有这个API的相关使用场景- 例如,多个读者和一个写者的问题可以使用这个API - 当写者已经获得了锁,所有的读者都被放在等待队列 - 当写者完成后,它可以用wake_up_all()唤醒在等待队列中的所有进程。 所有的读者会成功获得锁。
睡觉的另一种方法是睡眠一定的时间段。 进程可以以jiffies或毫秒/秒形式睡眠。 下面是以毫秒形式睡眠的示例代码。
[cpp] view plaincopy
- read_done = 0;
- while (read_done == 0) {
- msleep(2); //sleep for a couple of milliseconds.
- }
- // Another thread
- read_done = 1;
这个进程不知道它要花多少时间,但是它确保不会需要很长时间 - 因此它选择了避免创建另一个等待队列,而是简单地使用msleep()API来睡2毫秒。 迟早,条件变成真然后进程会继续处理。这带来上下文切换等方面的一些小的CPU开销,但它是一个简单的设计。 顺便说一句,如果我们想用jiffies睡眠的话,可以使用schedule_timeout()API。 它的内部处理是,把进程加入了某个等待队列,然后到了时间后唤醒它。 msleep()也是做同样的事情。
Linux 内核睡眠的几种方式的更多相关文章
- linux内核debug的一种方式:procfs
#include <linux/module.h> #include <linux/compat.h> #include <linux/types.h> #incl ...
- linux内核睡眠状态解析
1. 系统睡眠状态 睡眠状态是整个系统的全局低功耗状态,在这种状态下,用户空间的代码不能被执行并且整个系统的活动明显被降低 1.1 被支持的睡眠状态 取决于所运行平台的能力和配置选项,Linux内核能 ...
- 设置 Linux 下打印机的几种方式
设置 Linux 下打印机的几种方式 一.使用 cups 进行设置 如若遇到 cups 也没有驱动的话可以前往 openprinting.org 找寻对应驱动. 二.前往 official 下载驱动 ...
- linux创建文件的四种方式(其实是两种,强行4种)
linux创建文件的四种方式: 1.vi newfilename->i->编辑文件->ESC->:wq! 2.touch newfilename 3.cp sourcePath ...
- Linux 软件安装的三种方式
Linux 软件安装的三种方式 1.yum 语法格式: yum -y install package.name -y yes # 遇到提示自动输入yes 案例: 安装ifconfig命 ...
- Linux 安装 Nodejs 的两种方式
Linux 安装 Nodejs 的两种方式 目录 Linux 安装 Nodejs 的两种方式 一.压缩包安装 Nodejs 二.源码编译安装 Nodejs 一.压缩包安装 Nodejs 下载 Node ...
- Linux下定时执行任务的几种方式
如果说我说如果,你的某一个目录下会经常的生成一些垃圾文件,比如访问日志.错误日志.core文件,而你又不想过几分钟就去手动检查一下,那么可以使用定时执行任务的方式来解决.目前我所知道的可以执行定时任务 ...
- linux异步IO的两种方式【转】
转自:https://blog.csdn.net/shixin_0125/article/details/78898146 知道异步IO已经很久了,但是直到最近,才真正用它来解决一下实际问题(在一个C ...
- Linux内核替换的一种简单方法
前言 使用现有centos的镜像,在海光机器上出现了无法运行的情况,grub引导后就只剩下光标一直在闪,无任何字符输出.这种情况大概率是因为Linux的内核无法运行在海光的CPU上所导致的. 已得知L ...
随机推荐
- linux Generating /run/initramfs/rdsosreport.txt 问题
Generating /run/initramfs/rdsosreport.txt 问题 实验室异常断电,导致Centos7重启以后出现 Generating "/run/initramfs ...
- SpringMVC学习笔记-REST风格请求实现
RESTful概念及功能 RESTful的概念:RESTful是 一种资源定位及资源操作的风格,其本身既不是标准也不是协议,而是一种设计风格,可以使得软件整体层次更加分明.代码更加简洁,并且有利于实现 ...
- 最小生成树,Prim算法与Kruskal算法,408方向,思路与实现分析
最小生成树,Prim算法与Kruskal算法,408方向,思路与实现分析 最小生成树,老生常谈了,生活中也总会有各种各样的问题,在这里,我来带你一起分析一下这个算法的思路与实现的方式吧~~ 在考研中呢 ...
- 通过Maven打jar包&运行
运行命令:java -jar [包名] https://www.cnblogs.com/jinjiyese153/p/9374015.html
- CF1513F Swapping Problem(模型转化)
题目描述 You are given 2 arrays a a a and b b b , both of size n n n . You can swap two elements in b b ...
- maven把依赖打进jar包
1.把依赖打进sigma-api的jar包 <?xml version="1.0" encoding="UTF-8"?> <project x ...
- Octave Convolution卷积
Octave Convolution卷积 MXNet implementation 实现for: Drop an Octave: Reducing Spatial Redundancy in Conv ...
- CMOS图像传感器理解
CMOS图像传感器理解 水流方向从左边流向右边,上面有一个开关,拧下去的时候水流停止,拧上去的时候水流打开.左边是水流的源头我们给它起个名字,叫做源端(就是源头的意思嘛),右边是水流出去的地方,也就是 ...
- 3D结构光
3D结构光 3D结构光的整个系统包含结构光投影设备.摄像机.图像采集和处理系统.其过程就是投影设备发射光线到被测物体上,摄像机拍摄在被测物体上形成的三维光图形,拍摄图像经采集处理系统处理后获得被测物体 ...
- Ascend Pytorch算子适配层开发
Ascend Pytorch算子适配层开发 适配方法 找到和PyTorch算子功能对应的NPU TBE算子,根据算子功能计算出输出Tensor的size,再根据TBE算子原型构造对应的input/ou ...