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 ...
随机推荐
- 8.12-14 df 、mkswap、swapon、swapoff、sync
8.12 df:报告文件系统磁盘空间的使用情况 -a 显示所有文件系统 -h 以容易理解的格式显示磁盘的使用情况端 -i 显示文件系统的inode信息迷 -t 显示指定类型 ...
- 实操笔记:为 NSQ 配置监控服务的心路历程
在 Go 语言实现的实时消息队列中, NSQ 的热度可以排第一. NSQ 这款消息中间件简单易用,其设计目标是为在分布式环境下运行,为去中心化服务提供一个强大的基础架构.它具有分布式.去中心化的拓扑结 ...
- spark-steaming的exactly-once
spark实时计算中会存在数据丢失和数据重复计算的场景, 在receiver收到数据且通过driver的调度executor开始计算数据的时候如果driver突然崩溃,则此时executor就会被杀掉 ...
- Structured Streaming编程 Programming Guide
Structured Streaming编程 Programming Guide Overview Quick Example Programming Model Basic Concepts Han ...
- 旷视MegEngine基本概念
旷视MegEngine基本概念 MegEngine 是基于计算图的深度神经网络学习框架. 本文简要介绍计算图及其相关基本概念,以及它们在 MegEngine 中的实现. 计算图(Computation ...
- TensorFlow损失函数
TensorFlow损失函数 正如前面所讨论的,在回归中定义了损失函数或目标函数,其目的是找到使损失最小化的系数.本文将介绍如何在 TensorFlow 中定义损失函数,并根据问题选择合适的损失函数. ...
- 用NVIDIA Tensor Cores和TensorFlow 2加速医学图像分割
用NVIDIA Tensor Cores和TensorFlow 2加速医学图像分割 Accelerating Medical Image Segmentation with NVIDIA Tensor ...
- python_selenium_键盘事件
引言 ----在实际的web测试工作中,需要配合键盘按键来操作,webdriver的 keys()类提供键盘上所有按键的操作,还可以模拟组合键Ctrl+a,Ctrl+v等. 举例: #cording ...
- springcloud-config配置异常Cannot clone or checkout repository 和 Authentication is required but no CredentialsProvider has been registered解决过程
Cannot clone or checkout repository, 出现这个异常,通过检查是因为自己本地没有配置 ssh,所以配置了, https://blog.csdn.net/zy_2818 ...
- 【零基础学深度学习】动手学深度学习2.0--tensorboard可视化工具简单使用
1 引言 老师让我将线性回归训练得出的loss值进行可视化,于是我使用了tensorboard将其应用到Pytorch中,用于Pytorch的可视化. 2 环境安装 本教程代码环境依赖: python ...