译至: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

  1. //Process A:
  2. spin_lock(&list_lock);
  3. if(list_empty(&list_head)) {
  4. spin_unlock(&list_lock);
  5. set_current_state(TASK_INTERRUPTIBLE);
  6. schedule();
  7. spin_lock(&list_lock);
  8. }
  9. /* Rest of the code ... */
  10. spin_unlock(&list_lock);
  11. //Process B:
  12. spin_lock(&list_lock);
  13. list_add_tail(&list_head, new_node);
  14. spin_unlock(&list_lock);
  15. wake_up_process(processA_task);

上面的一段代码会导致一个“无效唤醒”的竞争条件问题。 说明如下:该进程对一些条件检查,然后设置任务状态为可中断并进入睡眠。 这时可能有一个小的竞争条件,当满足该条件的进程在条件检查之后唤醒睡眠进程时(唤醒任务仅仅是将任务状态设置成RUNNING,并将它保持在运行队列) - 这会导致一种情况:睡眠进程在唤醒进程将其唤醒后进入睡眠 - 这就是无效唤醒的问题。 这样做的后果可能会很严重也可能并不严重。 如果睡眠进程将条件标记为假,然后继续睡眠,那么这个无效唤醒的问题将导致睡眠进程永远保持该状态。 但是,如果条件是通过外部满足的话,那么最终条件将变为真,唤醒进程将唤醒睡眠进程。 这种情况的解决方法是在检查前设置任务状态 - 因此,如果这个进程进入睡眠状态,那么它将保持在运行队列而不是等待队列。 如果任务状态是running的话,schedule() API将保持进程只在运行队列。

还有一个问题,这种形式的睡眠要求waker进程中必须知道睡眠进程的task_struct。当存在一个以上的睡眠进程时这可能令人厌倦。 因此,在内核中睡眠的另一种形式是使用等待队列。 下面是一个示例一段代码,声明了一个等待队列,并把自己保持在等待队列。

[cpp] view plaincopy

  1. DECLARE_WAIT_QUEUE_HEAD(my_event);
  2. wait_event_interruptible(my_event, (cond == x));
  3. void my_wake_up(void)
  4. {
  5. if (cond == x)
  6. return;
  7. set_bit(2, &my_flags);
  8. wake_up_interruptible(&my_event);
  9. }

正如在上面这段代码中可以看出,当我们在一个队列中等待时,我们也传递了一个条件用于检查 - 这样内核在将进程保持在等待队列之前要确保这个条件不为真。内核将改变进程的状态,然后检查条件,并把该进程中加入等待队列。 当时间到时,waker进程将来唤醒​​等待队列上进程 - 这样,它不需要知道哪些进程正在睡眠,它只需知道等待队列。 在一定程度上比之前的不可扩展的睡眠形式更好。 还有一个API,wake_up_all(),将唤醒所有的进程 - 这个API如果不能正确使用会导致惊群问题。 不过,也有这个API的相关使用场景- 例如,多个读者和一个写者的问题可以使用这个API - 当写者已经获得了锁,所有的读者都被放在等待队列 - 当写者完成后,它可以用wake_up_all()唤醒在等待队列中的所有进程。 所有的读者会成功获得锁。

睡觉的另一种方法是睡眠一定的时间段。 进程可以以jiffies或毫秒/秒形式睡眠。 下面是以毫秒形式睡眠的示例代码。

[cpp] view plaincopy

  1. read_done = 0;
  2. while (read_done == 0) {
  3. msleep(2); //sleep for a couple of milliseconds.
  4. }
  5. // Another thread
  6. read_done = 1;

这个进程不知道它要花多少时间,但是它确保不会需要很长时间 - 因此它选择了避免创建另一个等待队列,而是简单地使用msleep()API来睡2毫秒。 迟早,条件变成真然后进程会继续处理。这带来上下文切换等方面的一些小的CPU开销,但它是一个简单的设计。 顺便说一句,如果我们想用jiffies睡眠的话,可以使用schedule_timeout()API。 它的内部处理是,把进程加入了某个等待队列,然后到了时间后唤醒它。 msleep()也是做同样的事情。

Linux 内核睡眠的几种方式的更多相关文章

  1. linux内核debug的一种方式:procfs

    #include <linux/module.h> #include <linux/compat.h> #include <linux/types.h> #incl ...

  2. linux内核睡眠状态解析

    1. 系统睡眠状态 睡眠状态是整个系统的全局低功耗状态,在这种状态下,用户空间的代码不能被执行并且整个系统的活动明显被降低 1.1 被支持的睡眠状态 取决于所运行平台的能力和配置选项,Linux内核能 ...

  3. 设置 Linux 下打印机的几种方式

    设置 Linux 下打印机的几种方式 一.使用 cups 进行设置 如若遇到 cups 也没有驱动的话可以前往 openprinting.org 找寻对应驱动. 二.前往 official 下载驱动 ...

  4. linux创建文件的四种方式(其实是两种,强行4种)

    linux创建文件的四种方式: 1.vi newfilename->i->编辑文件->ESC->:wq! 2.touch newfilename 3.cp sourcePath ...

  5. Linux 软件安装的三种方式

    Linux 软件安装的三种方式 1.yum ​ 语法格式: ​ yum -y install package.name ​ -y yes # 遇到提示自动输入yes ​ 案例: 安装ifconfig命 ...

  6. Linux 安装 Nodejs 的两种方式

    Linux 安装 Nodejs 的两种方式 目录 Linux 安装 Nodejs 的两种方式 一.压缩包安装 Nodejs 二.源码编译安装 Nodejs 一.压缩包安装 Nodejs 下载 Node ...

  7. Linux下定时执行任务的几种方式

    如果说我说如果,你的某一个目录下会经常的生成一些垃圾文件,比如访问日志.错误日志.core文件,而你又不想过几分钟就去手动检查一下,那么可以使用定时执行任务的方式来解决.目前我所知道的可以执行定时任务 ...

  8. linux异步IO的两种方式【转】

    转自:https://blog.csdn.net/shixin_0125/article/details/78898146 知道异步IO已经很久了,但是直到最近,才真正用它来解决一下实际问题(在一个C ...

  9. Linux内核替换的一种简单方法

    前言 使用现有centos的镜像,在海光机器上出现了无法运行的情况,grub引导后就只剩下光标一直在闪,无任何字符输出.这种情况大概率是因为Linux的内核无法运行在海光的CPU上所导致的. 已得知L ...

随机推荐

  1. 03丨认识文档数据库MongoDB

  2. nginx反向代理网站镜像

    某些公司会墙特定网站,如果你有一个可访问的域名和服务器,就可以通过nginx反向代理来来解决这些问题.比如现在我们用mirror.example.com镜像www.baidu.com,以下是详细操作. ...

  3. 路由信息相关 route 网卡

    目录 route命令 1.查看路由表 2.管理路由 基本网络配置 添加网卡地址 修改网卡UUID route命令 路由表管理命令,路由表主要构成: Destination: 目标网络ID,表示可以到达 ...

  4. 字符串算法(string_algorithm)

    format 作用 格式化输出对象,可以不改变流输出状态实现类似于printf()的输出 头文件 #include <boost/format.hpp> using namespace b ...

  5. IDEA 通过ctrl+滚轮缩放字体大小

    能用图解决的问题,尽量简单粗暴通俗易懂 1.第一种方式 2.第二种方式

  6. Python+Selenium学习笔记15 - 读取txt和csv文件

    读取txt的内容并用百度查找搜索 1 # coding = utf-8 2 3 from selenium import webdriver 4 import time 5 6 # 打开浏览器 7 d ...

  7. C# MVC(File)控件多张图片上传加预览

    刚来公司实习,老板叫我写一个积分商城网站.用的是公司的框架结构搭建的后台,所以后台的图片上传不需要自己写.但是前台的评价图片就需要自己手写了,在网上找了很多代码发现都用不了.问了很多人也都没有实现! ...

  8. 如何挑选深度学习 GPU?

    如何挑选深度学习 GPU? 深度学习是一个对计算有着大量需求的领域,从一定程度上来说,GPU的选择将从根本上决定深度学习的体验.因此,选择购买合适的GPU是一项非常重要的决策.那么2020年,如何选择 ...

  9. Velodyne VLP-16激光雷达数据分析

    Velodyne VLP-16激光雷达数据分析 Velodyne VLP-16激光雷达保持了 Velodyne 在 LiDAR 中的突破性重要功能:实时收发数据.360 度全覆盖.3D 距离测量以及校 ...

  10. 基于ARM Cortex-M的SoC存储体系结构和实战

    基于ARM Cortex-M的SoC存储体系结构和实战 System on Chip Architecture Tutorial Memory Architecture for ARM Cortex- ...