进程调度一 进程的介绍

一、进程介绍:

1、什么是进程:

  进程 = 程序 + 执行,进程是系统进行资源分配和调度的一个独立单位。

  进程的鼻祖,idle进程(pid = 0)  =>  kernel kthread进程(pid = 2);

                                                              =>   用户进程都是通过Init(pid = 1)进程创建;

2、进程和线程的区别是什么?

  线程被称为轻量级的进程;线程和进程的区别在于进程拥有独立的资源空间,线程则共享进程的资源空间;

线程是进程的一个实体,CPU调度和分派的基本单位。

3、进程的状态:

  struct task_struct   *task;

  task_struct-> state //volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */

(1)可运行状态(TASK_RUNNING)(R状态):进程正在执行,或者在队列中等待执行。

(2)可中断的等待状态(TASK_INTERRUPTIBLE)(S状态)(浅度睡眠):

  等待资源到来是唤醒,也可以通过其他进程信号或时钟中断唤醒,进入运行队列。

(3)不可中断的等待状态(TASK_UNINTERRUPTIBLE)(D状态):

  不可被其他进程信号或时钟中断唤醒,只有它所等待的资源可用的时候,他才会被唤醒。

(4)暂停状态(TASK_STOPPED)(T状态):

  进程暂停执行接受某种处理。如正在接受调试的进程处于这种状态。

(5)僵尸状态(TASK_ZOMBIE)(Z状态):

  进程已经结束但未释放PCB,父进程还没有调用wait()系统调用。一旦父进程调用了wait(),

  进程描述符就会被释放。

4、进程的类型:

(1)实时进程:

  对整体时延有严格要求的进程,比如VR设备对进程的实时性要求非常高,否则会造成晕眩;

(2)交互式进程:

  人机交互的进程,和鼠标、键盘、触摸屏等相关的应用;

(3)批处理进程:

  默默的工作和付出,可能会占用比较多的系统资源,如代码编译;

二、进程的描叙(task_struct)

  Linux内核通过一个被称为进程描述符的task_struct结构体来管理进程,这个结构体包含了一个进程所需的

所有信息。它定义在include/linux/sched.h文件中。

1、进程的状态:

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

  进程的可能状态值有很多:

//kernel-4.9/include/linux/sched.h
#define TASK_RUNNING		0
#define TASK_INTERRUPTIBLE	1
#define TASK_UNINTERRUPTIBLE	2
#define __TASK_STOPPED		4
#define __TASK_TRACED		8
/* in tsk->exit_state */
#define EXIT_DEAD		16
#define EXIT_ZOMBIE		32
......

2、进程PID:

  pid_t pid;
  pid_t tgid;

  PID的取值范围是0到32767,即系统中的进程数最大为32768个。

3、进程优先级:

	int prio, static_prio, normal_prio;
	unsigned int rt_priority;
prio 动态优先级
static_prio 静态优先级
normal_prio 取决于静态优先级和调度策略
rt_priority 实时优先级

(1)静态优先级static_prio:

  • 0 ~ 99 用于real-time processes,100 – 139用于普通进程;
  • 用户空间可以通过nice()或者setpriority对该静态优先级进行修改,通过getpriority可以获取该值;
  • 新创建的进程会继承父进程的static priority;
  • 修改了静态优先级,那么normal priority和动态优先级都需要重新计算。

(2)实时优先级rt_priority:

  从用户空间的视角来看的scheduling priority,0是普通进程,1~99是实时进程,99的优先级最高。

(3)normal_prio归一化优先级:

  normal_prio 的值取决于静态优先级和调度策略,可以通过 _setscheduler 函数来设置 normal_prio 的值 。

对于非实时进程,normal_prio 的值就等于静态优先级值 static_prio;对于实时进程:

normal_prio = MAX_RT_PRIO-1 - p->rt_priority。代码如下:

static inline int normal_prio(struct task_struct *p)
{
	int prio;
	if (task_has_dl_policy(p))
        //deadline的进程比RT进程和normal进程的优先级还要高,它的归一化优先级是负数:-1
		prio = MAX_DL_PRIO-1; 
	else if (task_has_rt_policy(p))
        //实时进程的优先级和normalized priority和rt_priority有关
		prio = MAX_RT_PRIO-1 - p->rt_priority;
	else
        //普通进程,normalized priority就是其静态优先级
		prio = __normal_prio(p);
	return prio;
}

(4)动态优先级prio:

  设定动态优先级的代码:p->prio = effective_prio(p),代码如下:

static int effective_prio(struct task_struct *p)
{
	p->normal_prio = normal_prio(p);
	/*
	 * If we are RT tasks or we were boosted to RT priority,
	 * keep the priority unchanged. Otherwise, update priority
	 * to the normal priority:
	 */
	if (!rt_prio(p->prio))
		return p->normal_prio;
	return p->prio;
}

4、进程调度相关:

(1)调度策略:

  unsigned int policy;

/*
 * Scheduling policies
 */
#define SCHED_NORMAL		0
#define SCHED_FIFO		1
#define SCHED_RR		2
#define SCHED_BATCH		3
/* SCHED_ISO: reserved but not implemented yet */
#define SCHED_IDLE		5
#define SCHED_DEADLINE		6

(2)调度类:

  const struct sched_class  *sched_class;

extern const struct sched_class stop_sched_class;
extern const struct sched_class dl_sched_class;
extern const struct sched_class rt_sched_class;//实时线程调度类
extern const struct sched_class fair_sched_class;//CFS公平调度类
extern const struct sched_class idle_sched_class;

  linux系統中,Scheduling Class的优先级顺序为StopTask > RealTime > Fair > IdleTask。

(3)调度实体:

  struct sched_entity  se;    //普通进程的调用实体
  struct sched_rt_entity  rt;         //实时进程的调用实体

  其中调度队列runqueue和调度实体之间的关系如下:

调度类

描述

  调度策略

dl_sched_class

deadline调度器

SCHED_DEADLINE

rt_sched_class

实时调度器

SCHED_FIFOSCHED_RR

fair_sched_class

完全公平调度器

SCHED_NORMALSCHED_BATCH

idle_sched_class

idle task

SCHED_IDLE

  每个CPU都会有一个全局的就绪队列(cpu runqueue),使用struct rq结构体描述管理就绪态的

struct sched_entity调度实体,struct rt_rq是实时调度器就绪队列,struct dl_rqDeadline调度器就绪队列。

5、内核栈:

struct task_struct {
        ......
	void *stack;//指向内核栈的指针
}

  每一个进程都对应一个task_struct的结构体,每一个task_struct对应一个内核栈stack,对于32bit的系统,

此结机构体的大小为8KB,64bit的为16KB,内核栈和thread_info以及task_struct关系如下图:

  内核有一个current的变量用于获取当前进程的task_struct的结构体的地址,

#include <linux/thread_info.h>
#define get_current() (current_thread_info()->task)
#define current get_current()

  此current变量来自于thread_info->task,这样通过SP寄存器获取当前内核栈stack的地址,对齐后可以

获得struct thread_info数据结构,自然就能获取到task_struct的信息的。下面看thread_info的结构:

struct thread_info {
	unsigned long		flags;		/* low level flags */
	int			preempt_count;	/* 0 => preemptable, <0 => bug */
	mm_segment_t		addr_limit;	/* address limit */
	struct task_struct	*task;		/* main task structure */
	__u32			cpu;		/* cpu */
	__u32			cpu_domain;	/* cpu domain */
	struct cpu_context_save	cpu_context;	/* cpu context */
	__u32			syscall;	/* syscall number */
	__u8			used_cp[16];	/* thread used copro */
	unsigned long		tp_value[2];	/* TLS registers */
#ifdef CONFIG_CRUNCH
	struct crunch_state	crunchstate;
#endif
	union fp_state		fpstate __attribute__((aligned(8)));
	union vfp_state		vfpstate;
#ifdef CONFIG_ARM_THUMBEE
	unsigned long		thumbee_state;	/* ThumbEE Handler Base register */
#endif
	int			cpu_excp;
	void			*regs_on_excp;
};

(1)preempt_count

preempt_count代表的是该进程是否可以被抢占,根据注释的说明当peermpt_count等于0的时候当前进程

就可以被抢占,当小于0存在bug,当不等于0也就是大于0说明当前进程不可以被抢占。不可抢占的原因很多,

比如当前进程在中断上下文中或者使用了锁(spin_lock的过程中会disable掉抢占的)。

#define preempt_disable() \
do { \
	preempt_count_inc(); \
	barrier(); \
} while (0)

#define preempt_enable() \
do { \
	barrier(); \
	preempt_count_dec(); \
} while (0)

#define preempt_count_inc() preempt_count_add(1)
#define preempt_count_dec() preempt_count_sub(1)

spin_lock     -> preempt_disable     ===> preempt_count  + 1

spin_unlock -> preempt_enable      ===> preempt_count  - 1

(2)struct task_struct    *task;

  指向对应struct task_sturct描叙符;

三、总结:

  学习进程管理,需要了解进程的如下信息,后续会继续介绍进程管理的其他内容:

  • 进程的状态
  • 进程的类型
  • 进程的优先级
  • 进程的调度策略
  • 进程众多结构体的关系

作者:frank_zyp
您的支持是对博主最大的鼓励,感谢您的认真阅读。
本文无所谓版权,欢迎转载。

猜你喜欢

转载自blog.csdn.net/frank_zyp/article/details/85295849