linux中进程定义,(一)Linux进程调度器-基础

/* Used in tsk->exit_state: */#define EXIT_DEAD 0x0010#define EXIT_ZOMBIE 0x0020#define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD)

/* Used in tsk->state again: */#define TASK_PARKED 0x0040#define TASK_DEAD 0x0080#define TASK_WAKEKILL 0x0100#define TASK_WAKING 0x0200#define TASK_NOLOAD 0x0400#define TASK_NEW 0x0800#define TASK_STATE_MAX 0x1000

/* Convenience macros for the sake of set_current_state: */#define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)#define TASK_STOPPED (TASK_WAKEKILL | __TASK_STOPPED)#define TASK_TRACED (TASK_WAKEKILL | __TASK_TRACED)

#define TASK_IDLE (TASK_UNINTERRUPTIBLE | TASK_NOLOAD)

2.3 scheduler 调度器

8a43d0700a0739c7934043849e1ed69f.png

所谓调度,就是按照某种调度的算法,从进程的就绪队列中选取进程分配CPU,主要是协调对CPU等的资源使用。进程调度的目标是最大限度利用CPU时间。

内核默认提供了5个调度器,Linux内核使用 struct sched_class 来对调度器进行抽象:

Stop调度器, stop_sched_class :优先级最高的调度类,可以抢占其他所有进程,不能被其他进程抢占;

Deadline调度器, dl_sched_class :使用红黑树,把进程按照绝对截止期限进行排序,选择最小进程进行调度运行;

RT调度器, rt_sched_class :实时调度器,为每个优先级维护一个队列;

CFS调度器, cfs_sched_class :完全公平调度器,采用完全公平调度算法,引入虚拟运行时间概念;

IDLE-Task调度器, idle_sched_class :空闲调度器,每个CPU都会有一个idle线程,当没有其他进程可以调度时,调度运行idle线程;

Linux内核提供了一些调度策略供用户程序来选择调度器,其中 Stop调度器 和 IDLE-Task调度器 ,仅由内核使用,用户无法进行选择:

SCHED_DEADLINE :限期进程调度策略,使task选择 Deadline调度器 来调度运行;

SCHED_RR :实时进程调度策略,时间片轮转,进程用完时间片后加入优先级对应运行队列的尾部,把CPU让给同优先级的其他进程;

SCHED_FIFO :实时进程调度策略,先进先出调度没有时间片,没有更高优先级的情况下,只能等待主动让出CPU;

SCHED_NORMAL :普通进程调度策略,使task选择 CFS调度器 来调度运行;

SCHED_BATCH :普通进程调度策略,批量处理,使task选择 CFS调度器 来调度运行;

SCHED_IDLE :普通进程调度策略,使task以最低优先级选择 CFS调度器 来调度运行;2.4 runqueue 运行队列

a05e86fe79f8deaf00f07944f3ed03fd.png

每个CPU都有一个运行队列,每个调度器都作用于运行队列;

分配给CPU的task,作为调度实体加入到运行队列中;

task首次运行时,如果可能,尽量将它加入到父task所在的运行队列中(分配给相同的CPU,缓存affinity会更高,性能会有改善);

Linux内核使用 struct rq 结构来描述运行队列,关键字段如下:

/** This is the main, per-CPU runqueue data structure.** Locking rule: those places that want to lock multiple runqueues* (such as the load balancing or the thread migration code), lock* acquire operations must be ordered by ascending &runqueue.*/struct rq {/* runqueue lock: */raw_spinlock_t lock;/** nr_running and cpu_load should be in the same cacheline because* remote CPUs use both these fields when doing load calculation.*/unsigned int nr_running;/* 三个调度队列:CFS调度,RT调度,DL调度 */struct cfs_rq cfs;struct rt_rq rt;struct dl_rq dl;

/* stop指向迁移内核线程, idle指向空闲内核线程 */struct task_struct *curr, *idle, *stop;/* ... */}

2.5 task_group 任务分组

b42880b077c8f8d517165caceeaee77a.png

利用任务分组的机制,可以设置或限制任务组对CPU的利用率,比如将某些任务限制在某个区间内,从而不去影响其他任务的执行效率;

引入 task_group 后,调度器的调度对象不仅仅是进程了,Linux内核抽象出了 sched_entity/sched_rt_entity/sched_dl_entity 描述调度实体,调度实体可以是进程或 task_group ;

使用数据结构 struct task_group 来描述任务组,任务组在每个CPU上都会维护一个 CFS调度实体、CFS运行队列,RT调度实体,RT运行队列 ;

Linux内核使用 struct task_group 来描述任务组,关键的字段如下:

/* task group related information */structtask_group{/* ... *//* 为每个CPU都分配一个CFS调度实体和CFS运行队列 */# ifdefCONFIG_FAIR_GROUP_SCHED/* schedulable entities of this group on each cpu */structsched_entity** se;/* runqueue "owned" by this group on each cpu */structcfs_rq** cfs_rq;unsignedlongshares;# endif

/* 为每个CPU都分配一个RT调度实体和RT运行队列 */# ifdefCONFIG_RT_GROUP_SCHEDstructsched_rt_entity** rt_se;structrt_rq** rt_rq;

structrt_bandwidthrt_bandwidth;# endif

/* task_group之间的组织关系 */structrcu_headrcu;structlist_headlist;

structtask_group* parent;structlist_headsiblings;structlist_headchildren;

/* ... */};

3. 调度程序

调度程序依靠几个函数来完成调度工作的,下边将介绍几个关键的函数。

主动调度 - schedule

8beb81f892e8fdf1f3cb7e9cc0b3fec8.png

schedule 函数,是进程调度的核心函数,大体的流程如上图所示。

核心的逻辑:选择另外一个进程来替换掉当前运行的进程。进程的选择是通过进程所使用的调度器中的 pick_next_task 函数来实现的,不同的调度器实现的方法不一样;进程的替换是通过 context_switch 来完成切换的,具体的细节后续的文章再深入分析。

周期调度 - schedule_tick

5c66de742e3c304190ece9b40e800da8.png

时钟中断处理程序中,调用 schedule_tick 函数;

时钟中断是调度器的脉搏,内核依靠周期性的时钟来处理器CPU的控制权;

时钟中断处理程序,检查当前进程的执行时间是否超额,如果超额则设置重新调度标志( _TIF_NEED_RESCHED );

时钟中断处理函数返回时,被中断的进程如果在用户模式下运行,需要检查是否有重新调度标志,设置了则调用 schedule 调度;

高精度时钟调度 - hrtick

e757776afd8bd4cd3539f6e4bee748fd.png

高精度时钟调度,与周期性调度类似,不同点在于周期调度的精度为ms级别,而高精度调度的精度为ns级别;

高精度时钟调度,需要有对应的硬件支持;

进程唤醒时调度 - wake_up_process

9170f54da75b211814c265207b56897c.png

唤醒进程时调用 wake_up_process 函数,被唤醒的进程可能抢占当前的进程;

上述讲到的几个函数都是常用于调度时调用。此外,在创建新进程时,或是在内核抢占时,也会出现一些调度点。

本文只是粗略的介绍了一个大概,后续将针对某些模块进行更加深入的分析,敬请期待。返回搜狐,查看更多

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值