Linux进程调度

Linux进程调度

1、程序VS进程

程序是存放在磁盘上的一序列代码和数据的可执行映像,是一个静止的实体。

进程是一个执行中的程序,是动态的实体。

2、Linux进程的四大要素
<1>有一段供进程执行的程序,该程序可以被多个进程执行。
<2>:有进程专用的内核空间堆栈。
<3>:进程控制快(task_struct:有了这个数据结构,进程才能成为内核调度的一个基本单位接受内核的调度。

<4>:独立的用户空间

进程:有独立的进程空间

线程:只有前三条,没有第四条。

内核线程:完全没有用户空间。

用户线程:共享用户空间。

3、Linux进程分类:
<1>:交互式进程:这些进程经常和用户发生交互,所以花费一些时间等待用户的操作。当有输入时,进程必须很快的激活。通常,要求延迟在50-150毫秒。典型的交互式进程有:控制台命令,文本编辑器,图形应用程序。
<2>:批处理进程(Batch Process):不需要用户交互,一般在后台运行。所以不需要非常快的反应,他们经常被调度期限制。典型的批处理进程:编译器,数据库搜索引擎和科学计算。
<3>:实时进程:对调度有非常严格的要求,这种类型的进程不能被低优先级进程阻塞,并且在很短的时间内做出反应。典型的实时进程:音视频应用程序,机器人控制等。
批处理进程可能与I/O或者CPU有关,但是实时进程完全通过Linux的调度算法识别。
其实交互式进程和批处理进程很难区别。
4:Linux进程优先级
<1>、静态优先级(priority): 被称为“静态”是因为它不随时间而改变,只能由用户进行修改。它指明了在被迫和其它进程竞争CPU之前该进程所应该被允许的时间片的最大值(20)。

每个普通进程都一个静态优先级,内核为其分配的优先级数为:100(高优先级)-139(低优先级)。数值越大,优先级越低。新创建的进程一般继承父进程的优先级,但是用户可以通过给nice()函数传递“nice value“或者setpriority()改变优先级。

<2>:、动态优先级(counter): counter 即系统为每个进程运行而分配的时间片,Linux 兼用它来表示进程的动态优先级。只要进程拥有CPU,它就随着时间不断减小;当它为0 时,标记进程重新调度。它指明了在当前时间片中所剩余的时间量(最初为20)

事实上,在进程在调度的时候,调度器只察看动态优先级,其值为100-139。通过下面的公式可以根据静态优先计算出相应的动态优先级。
Dynamicy priority = max (100, min (static priority - bonus + 5, 139))   

Bonus:0-10,比5小,降低动态优先级,反之,可以提高动态优先级。Bonus和进程的平均睡眠时间有关。

<3>、 实时优先级(rt_priority):值为1000。Linux把实时优先级与counter值相加作为实时进程的优先权值。较高权值的进程总是优先于较低权值的进程,如果一个进程不是实时进程,
其优先权就远小于1000,所以实时进程总是优先。

<4>、Base time quantum:是由静态优先级决定,当进程耗尽当前Base time quantum,kernel会重新分配一个Base time quantum给它。静态优先级和Base time quantum的关系为:
(1)        当静态优先级小于120
      Base time quantum(in millisecond)= (140 – static priority) * 20
(2)        当静态优先级大于等于120
      Base time quantum(in millisecond)= (140 – static priority) * 5

5、
Linux 进程的调度算法
<1>、时间片轮转调度算法(round-robin):SCHED_RR,用于实时进程。系统使每个进程依次地按时间片轮流执行的方式。
<2>、优先权调度算法:SCHED_NORMAL,用于非实时进程。系统选择运行队列中优先级最高的进程运行。Linux 采用抢占式的优级算法,即系统中当前运行的进程永远是可运行进程中优先权最高的那个。
<3>、FIFO(先进先出) 调度算法:SCHED_FIFO,用于实时进程

 

6、Linux 进程的调度时机schedule()

方式:主动式和被动式

主动式:在内核中直接调用schedule()

current->state=TASK_INTERRUPTIBLE

                          TASK_RUNNING

被动式:用户抢占——从系统调用或者中断处理程序返回用户空间

                内核抢占——在不支持内核抢占的系统中,进程一旦运行于内核空间就可以一直运行,直到它主动放弃或者时间片耗尽。

                                        在支持内核抢占的系统中,更高优先级的进程可以抢占正在内核空间运行的低优先级进程。
有些特例是不允许抢占的。

<1>、内核正在中断处理

<2>、内核正在中断上下文的Bottom Half处理

<3>、进程正持有Spinlock自旋锁

<4>、内核正在执行调度程序schedule()

 

 

7、代码分析

<1>、2.6 版的内核仍然用 task_struct 来表征进程,尽管对线程进行了优化,但线程的内核表示仍然与进程相同。随着调度器的改进,task_struct 的内容也有了改进,交互式进程优先支持、内核抢占支持等新特性,在task_struct 中都有所体现。在 task_struct 中,有的属性是新增加的,有的属性的值的含义发生了变化,而有的属性仅仅是改了一下名字。可称为进程控制块(TCB),主要包含进程标识符、优先级、堆栈空间、进程状态

task_struct源代码定义在kernel/include/Linux/sched.h中

struct task_struct {

        volatile longstate;   /* -1 unrunnable, 0 runnable, >0 stopped */

        structthread_info *thread_info;

        atomic_tusage;

        unsigned longflags;   /* per process flags, defined below */

        unsigned longptrace;

        int lock_depth;        /* Lock depth */

        int prio, static_prio;

        structlist_headrun_list;

        prio_array_t *array;

        unsigned long sleep_avg;

        long interactive_credit;

        unsigned long longtimestamp;

        int activated;

        unsigned long policy;

        cpumask_t cpus_allowed;

        unsigned int time_slice, first_time_slice;

        structlist_headtasks;

       /*

        * ptrace_list/ptrace_children formsthe list of my children

        * that were stolen by a ptracer.

         */

        structlist_head ptrace_children;

        structlist_head ptrace_list;

        structmm_struct *mm, *active_mm;
};


 

<2>、核心结构task_struct中的state

进程的状态仍然用 state 表示

#define TASK_RUNNING            0
#define TASK_INTERRUPTIBLE      1
#define TASK_UNINTERRUPTIBLE    2
#define TASK_STOPPED            4
#define TASK_ZOMBIE             8
#define TASK_DEAD               16

2.6新增加了两种状态:TRACED、DEAD。

新增加的TASK_DEAD指的是已经退出且不需要父进程来回收的进程。TASK_TRACED供调试使用。

原有的几个state:

TASK_ZOMBIE一个已经终止的但仍保留有任务的进程(已经死了,户口未注销)。

TASK_RUNNING就绪态(准确的说你应该是task_runable)

TASK_INTERRUPTIBLE、TASK_UNINTERRUPTIBLE不同深度的睡眠态

TASK_STOPPED描述一个已经停止的进程,当进程收到一个特殊信号或被时候ptrace系统调用的进程监控,并将监控权交给监控进程。Linux2.4版,内核在创建进程是,为每个进程配两个连续的物理页面(8KB)它的顶端(低地址部分)用来存储进程的task_struct结构(约1KB),剩下的约7KB就是进程的系统空间堆栈,内核可以通过栈寄存器指针ESP快速地方位该进程。

<3>thread_info

在linux2.6中。这两个页面顶端存放的不再是进程的整个task_struct结构,而是task_struct中的thread_info,task_struct的大部分信息保存在栈外,通过的task指针可以方便地访问到。

thread_info是描述一个描述任务的重要结构体,下面将看到thread_info的数据结构定义(/include/asm-386/thread_.h)

struct thread_info {
        struct task_struct      *task;          /* main task structure */
         struct exec_domain      *exec_domain;   /* execution domain */
         unsigned long           flags;          /* low level flags */
         unsigned long           status;         /* thread-synchronous flags */
         __u32                   cpu;            /* current CPU */
         __s32                   preempt_count; /* 0 => preemptable, <0 => BUG */
 
 
         mm_segment_t            addr_limit;     /* thread address space:
                                                    0-0xBFFFFFFF for user-thead
                                                    0-0xFFFFFFFF for kernel-thread
                                                 */
         struct restart_block    restart_block;
 
         unsigned long           previous_esp;   /* ESP of the previous stack in case
                                                    of nested (IRQ) stacks
                                                 */
         __u8                    supervisor_stack[0];
 };

一些主要的环境信息如下:

task指针指向其对应的任务控制块

preempt_count是用来表示内核能否被抢占的使能成员,如果它大于0.表示内核不能被抢占:如果等于0,则表示内核处于安全状态(即没有加锁),可以抢占。

Flags里面有一个TIF_NEED_RESCHED(调度标志)位,如果此标志位为1.则表示应该尽快启动调度器。

8、调度步骤

Schedule()函数工作流程:

<1>、清理当前运行中的进程

<2>、选择下一个要运行的进程

<3>、设置新进程的运行环境

<4>、进程上下文切换

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值