你好,游客 登录 注册 搜索
背景:
阅读新闻

Linux内核中的进程

[日期:2012-12-16] 来源:CSDN  作者:weiqing1981127 [字体: ]

多任务系统可以分为:非抢占式和抢占式。Linux提供抢占式多任务模式。进程在被抢占之前能够运行的时间叫进程的时间片,Linux独一无二的公平调度程序本身并没有采用时间片来达到公平调度。

Linux之前采用O(1)调度器,它对大服务器的工作负载很理想,但是对响应时间敏感的程序却有不足。在2.6.23内核版本中用完全公平调度算法(CFS)代替了O(1)调度算法。

 

进程可以被分为I/O消耗型和处理器消耗型。I/O消耗型指进程的大部分时间用来提交I/O请求或是等待I/O请求。处理器消耗型指进程把事件大多数用在执行代码上。调度策略通常在两个矛盾中寻找平衡:进程响应迅速和最大系统利用率。Linux更倾向于优先调度I/O消耗型进程。

 

调度程序总是选择时间片未用尽而且优先级最高的进程运行。

Linux采用两种不同的优先级范围。第一种是nice值,越大的nice值意味着更低的优先级。第二种是实时优先级,其值可以配置,越高的实时优先级数值意味着进程优先级越高。任何实时进程的优先级都高于普通进程。

 

CFS做法:允许每个进程运行一段时间,循环轮转,选择运行最少的进程作为下一个运行进程,而不再采用分配给每一个进程时间片的做法,CFS在所有可运行进程总数基础上计算出一个进程应该运行多久,而不是依靠nice值来计算时间片。CFS引入每个进程获得的时间片底线(最小粒度)默认情况为1ms,绝对的nice值不再影响调度决策,任何进程所获得的处理器时间由它自己和其他所有可运行进程nice值的相对差决定。

 

Linux调度的实现:

时间记账

调度器实体结构是struct sched_entity,它嵌入在进程描述符struct task_struct中。虚拟时间以ns为单位,存在vruntime变量中,它和定时器节拍不再相关,vruntime变量可以准确测定进程的运行时间,而且可以知道谁应该是下一个被运行的进程。

 

进程选择

当CFS需要选择下一个运行进程时,它会挑一个具有最小vruntime的进程,这就是CFS调度算法的核心:选择具有最小的vruntime的任务。这里采用红黑树实现的。

 

调度器入口

进程调度的主要入口点是schedule函数,该函数会以优先级为序,从高到低,依次检查每一个调度器,并且从最高优先级的调度器中,选择最高优先级的进程。

 

睡眠和唤醒

对于睡眠,内核的操作是:进程把自己标记为休眠状态,从可执行红黑树中移出,放入等待队列,然后调用schedule函数选择和执行一个其他进程。对于唤醒,正好相反,进程被设置为可执行状态,然后再从等待队列中移到可执行红黑树中。

 

休眠有两种进程状态:TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE。它们唯一的区别在于处在TASK_UNINTERRUPTIBLE的进程会忽略信号,处于TASK_INTERRUPTIBLE状态的进程如果接收到一个信号,会被提前唤醒并响应该信号。两种状态的进程位于同一个等待队列上,等待某些事情,不能够运行。

关于休眠还需要注意一点:存在虚假的唤醒,所以有时候需要一个循环处理来保证进程被唤醒的条件真正大达成。

等待队列的使用

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);  //定义等待队列头

wait_event_interruptible(button_waitq, ev_press);              //休眠

wake_up_interruptible(&button_waitq);                  //唤醒

 

 

抢占和上下文切换

上下文切换就是从一个可执行进程切换到另一个可执行进程。Schedule函数主要完成两个工作:其一,把虚拟内存从上一个进程映射切换到新进程中。其二,从上一个进程的处理器状态切换到新进程的处理器状态。

内核必须知道在什么时候调用schedule函数,如何仅靠用户程序代码显式地调用schedule,它们可能就会永远的执行下去,所以内核中提供了一个need_resched标志来表明是否需要重新执行一次调度,该标志对于内核来讲是一个信息,它表示有其他进程应当被运行了,要尽快调用调度程序。

用户抢占

内核即将返回用户空间的时候,如果need_resched标志被设置,会导致schedule函数被调用,此时就会发生用户抢占。用户抢占在如下情况时产生:其一,从系统调用返回用户空间时。其二,从中断处理程序返回用户空间时。

内核抢占

在2.6版内核中,内核引入抢占能力,只要重新调度是安全的,即只要没有持有锁,内核就可以在任何时候抢占正在执行的任务。为了支持内核抢占,在每个进程的thread_info引入preempt_count计数器,当做一把锁来使用。内核抢占在如下情况时产生:其一,中断处理程序正在执行,且返回内核空间之前。其二,内核代码再一次具有可抢占性的时候。其三,如果内核中的任务显式地调用schedule函数。其四,如果内核中的任务阻塞(这样会调用schedule函数)。

linux
相关资讯       Linux内核编程 
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数

       

评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款