2017-03-03


很遗憾之前在介绍进程调度的文章中,虽然涉及到了内核抢占,但是却没有对其进行深入介绍,今天就稍微总结下内核抢占。

  内核抢占在一定程度上减少了对某种事件的响应延迟,这也是内核抢占被引入的目的。之前的内核中,除了显示调用系统调度器的某些点,内核其他地方是不允许中重新调度的,如果内核在做一些比较复杂的工作,就会造成某些急于处理的事得不到及时响应。针对内核抢占其实本质上也是对当前进程而言(不知道这么描述是否合适),因为内核是为用户程序提供服务,换言之,其本身不会主动的去执行某个动作。这里内核抢占,重点在于用户程序请求内核服务时,CPU切换到内核态在执行某个系统服务期间,被抢占。

  当然,即使支持内核抢占,也不是什么时候都可以的,还是要考虑对临界区的保护。类似于多处理器架构,如果进程A陷入到内核模式访问某个临界资源,而在访问期间,进程B也要访问临界区,如果这种抢占被允许,那么就发生了临界区被重入。所以,在访问临界资源时需要禁止内核抢占,在出临界区则要开启内核抢占。

  为了支持内核抢占,在进程结构体的thread_info结构中有个preempt_count字段,用以记录当前内核(活动)是否可以被抢占。当该值为0时,允许被抢占;否则,不允许。

  关于内核抢占有几个函数:
  

#define preempt_disable() \
do { \
inc_preempt_count(); \
barrier(); \
} while () #define preempt_enable() \
do { \
preempt_enable_no_resched(); \
barrier(); \
preempt_check_resched(); \
} while ()
#define inc_preempt_count() add_preempt_count(1)
#define dec_preempt_count() sub_preempt_count(1) # define add_preempt_count(val) do { preempt_count() += (val); } while (0)
# define sub_preempt_count(val) do { preempt_count() -= (val); } while (0)

上面两个函数是禁止和启用内核抢占。其实就是一个宏定义。禁止内核抢占本质上就是把当前进程的thread_info结构中的preempt_count字段加1,而启用内核抢占就是减1.注意这里启用内核抢占之后,调用了preempt_check_resched检查当前是否需要重新调度,这也是一个宏,实现如下:

#define preempt_check_resched() \
do { \
if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \
preempt_schedule(); \
} while ()

就是在开启内核抢占之后,检查下此时是否有比较重要的进程等待执行,如果有,则调用preempt_schedule函数执行调度,可见在显示开启内核抢占之后,是触发内核抢占的一个时机。而调度过程本身是不允许被抢占的。preempt_schedule函数如下

asmlinkage void __sched notrace preempt_schedule(void)
{
struct thread_info *ti = current_thread_info(); /*
* If there is a non-zero preempt_count or interrupts are disabled,
* we do not want to preempt the current task. Just return..
*/
if (likely(ti->preempt_count || irqs_disabled()))
return; do {
add_preempt_count_notrace(PREEMPT_ACTIVE);
__schedule();
sub_preempt_count_notrace(PREEMPT_ACTIVE); /*
* Check again in case we missed a preemption opportunity
* between schedule and now.
*/
barrier();
} while (need_resched());
}

如果抢占计数器不为0或者当前处于关闭硬件中断状态均是不可以被抢占的。

前面提到,在不支持内核抢占的内核中,内核态程序会一直执行,直到返回用户空间进程时,才会检查调度。在内核中执行期间,能打断当前执行的,只有中断,在硬件中断来了之后,处理器会根据情况着手处理硬件中断,在硬件中断处理完毕需要恢复现场时,若检查之前的状态是内核态,则不触发调度,只有之前状态是用户态时才会触发调度。而在支持内核抢占的内核中,在从硬件中断返回时,不管是返回用户态和内核态都会检查调度,若是返回内核态,检查当前线程调度标识和抢占标识,若都允许,则可进程调度。这是内核抢占下由增加的一个调度点。

参考资料:

1、linux 3.10.1内核

2、深入linux内核架构

Linux下的内核抢占的更多相关文章

  1. Linux下查看内核、CPU、内存及各组件版本的命令和方法

    Linux下查看内核.CPU.内存及各组件版本的命令和方法 Linux查看内核版本: uname -a                        more /etc/*release       ...

  2. Linux下编译内核配置选项简介

    Code maturity level options代码成熟度选项 Prompt for development and/or incomplete code/drivers 显示尚在开发中或尚未完 ...

  3. Linux 下 Oracle 内核参数优化

    数据库的性能优化涉及到整个数据库运行环境的方方面面,诸如操作系统,Oracle自身,存储,网络等等几个大块.而操作系统则是Oracle稳定运行与最大化性能的基石.本文主要描述基于Linux系统下 Or ...

  4. 优化Linux下的内核TCP参数以提高系统性能

    内核的优化跟服务器的优化一样,应本着稳定安全的原则.下面以64位的Centos5.5下的Squid服务器为例来说明,待客户端与服务器端建立 TCP/IP连接后就会关闭SOCKET,服务器端连接的端口状 ...

  5. 优化Linux下的内核TCP参数来提高服务器负载能力

    http://blog.renhao.org/2010/07/setup-linux-kernel-tcp-settings/ /proc/sys/net目录 所有的TCP/IP参数都位于/proc/ ...

  6. Linux下的内核测试工具——perf使用简介

    Perf是Linux kernel自带的系统性能优化工具.Perf的优势在于与Linux Kernel的紧密结合,它可以最先应用到加入Kernel的new feature.pef可以用于查看热点函数, ...

  7. linux下删除内核

    一.概述 笔者的Ubuntu系统刚安装成功后,就不知道怎么会有多个内核,但实际上默认运行的只有一个.在grub启动界面多余的启动项和多余内核占用的存储空间迫使我产生了铲除多余内核的冲动. 最近,自己从 ...

  8. 在linux下查看内核版本、gcc版本、操作系统多少位等参数

    1. 查看linux版本 cat /etc/issue Ubuntu 11.04 \n \l 2. 查看内核版本 1)cat /proc/version Linux version 2.6.38-13 ...

  9. linux下改动内核參数进行Tcp性能调优 -- 高并发

    前言: Tcp/ip协议对网络编程的重要性,进行过网络开发的人员都知道,我们所编写的网络程序除了硬件,结构等限制,通过改动Tcp/ip内核參数也能得到非常大的性能提升, 以下就列举一些Tcp/ip内核 ...

随机推荐

  1. The 14th UESTC Programming Contest Final B - Banana Watch 预处理、前缀和

    B - Banana Watch Time Limit: 1000/1000MS (Java/Others)     Memory Limit: 262144/262144KB (Java/Other ...

  2. hive表支持中文设置

    默认创建表时说明中带有中文字段时会显示如下乱码信息: 解决方案: 在hive的元数据库中执行以下SQL语句,然后重新创建刚才的表即可 . ) character set utf8; ) charact ...

  3. 采样方法(Sampling Methods)

    1.基本采样算法(Basic Sampling Algorithms) 1.1.标准概率分布(Standard distributions) 1.2.拒绝采样(Rejection sampling) ...

  4. java---多线程及线程的概念

    如果对什么是线程.什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内. 用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现.说这个话其 ...

  5. hdu 2918(IDA*)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2918 思路:这道题与前面几道类似,可以说是被秒杀了!!!构造启发式函数h()=(cnt+3)/4(cn ...

  6. selenium基础框架的封装(Python版)这篇帖子在百度关键词搜索的第一位了,有图为证,开心!

    百度搜索结果页地址:https://www.baidu.com/s?ie=utf-8&f=3&rsv_bp=1&rsv_idx=1&tn=baidu&wd=se ...

  7. kafka对比RocketMQ(转)

    淘宝内部的交易系统使用了淘宝自主研发的Notify消息中间件,使用Mysql作为消息存储媒介,可完全水平扩容,为了进一步降低成本,我们认为存储部分可以进一步优化,2011年初,Linkin开源了Kaf ...

  8. 使用jq获取文字的宽度

    获取字符串的长度很简单,但是如何获取一个字符串的字体宽度却是一个不太好操作的问题,今天查阅了许多资料,终于找到了解决方法: 1.首先,需要添加一个标签,HTML代码如下: <body> & ...

  9. AsyncTask--远程图片获取与本地缓存

    对于客户端——服务器端应用,从远程获取图片算是经常要用的一个功能,而图片资源往往会消耗比较大的流量,对应用来说,如果处理不好这个问题,那会让用户很崩溃,不知不觉手机流量就用完了,等用户发现是你的应用消 ...

  10. 如何访问局域网的Access数据库?

    1]用共享打印机来打开文件共享, 2]把Access文件.mdb所在的文件夹 共享,然后其他的就和本地一样了. 设置如下: Data Source="\\192.168.7.49\user\ ...