linux进程调度(一)-进程概述

一、什么是进程
进程是指计算机已运行的程序。程序本身只是指令、数据及其组织形式的描述。进程就是一个程序的执行实例,也就是正在执行的程序。在linux操作系统的中,进程就是一个担当分配系统资源CPU时间、内存的实体。进程控制的主要功能是对系统中的所有进程实施有效的管理,它具有创建新进程、撤销已有进程、实现进程状态之间的转换等功能。进程在运行中不断地改变其运行状态。一个进程在运行期间,不断地从一种状态转换到另一种状态,它可以多次处于就绪状态和执行状态,也可以多次处于阻塞状态。
目前,只有CPU的资源管理器能主动发起调度,而其他资源像内存,网络,显卡等资源管理器都是提供申请服务调度的,所以要必须理解我们常说的进程调度都是指调度CPU。

进程发展史的主要内容:

  1. 单道批处理系统时期:早期的计算机只支持运行单个程序,从磁带或卡片读入程序,由操作员操作控制运行。这种系统被称为单道批处理系统,没有多个程序共同运行的概念,也没有进程的概念。

  2. 多道批处理系统时期:20世纪60年代早期,随着计算机技术的发展,多道批处理操作系统应运而生,允许多个程序同时进入内存并在CPU上运行。这里的每个程序称为一个作业(Job),但是没有进程的概念。

  3. 分时操作系统时期:20世纪60年代中期,分时操作系统应运而生,引入了多用户的概念,这为进程的发展铺平了道路。在分时系统中,操作系统可以运行多个进程并为它们提供时间片,每个进程只有在它的时间片内获得CPU的控制权。这一时期UNIX系统的开发者对进程进行了深入的研究。

  4. 多任务操作系统时期:20世纪80年代,多任务操作系统开始出现,这种操作系统允许多个进程同时运行,每个进程都有自己的地址空间、寄存器和堆栈等。操作系统必须管理和控制各个进程的运行状态,这为进程的实现和管理提供了更大的灵活性和可控性。

  5. 现代操作系统时期:21世纪以来,随着计算机技术的不断发展,操作系统和进程的概念也在不断更新和完善。现代操作系统支持多核处理器、多线程和分布式系统等技术,允许进程在不同的计算机上运行,进一步增强了进程的灵活性和可扩展性。同时,在容器技术的发展下,进程管理变得更加高效和简单,如Docker等。

二、进程的生命周期
Linux操作系统是一个多任务操作系统。 系统中的各个进程可以分时复用CPU时间片,通过有效的进程调度策略,实现多任务并行执行。进程并不总是可以立即运行。有时候它必须等待来自外部信号源、不受其控制的事件,例如在文本编辑器中等待键盘输入。在事件发生之前,进程无法运行。进程可能有以下几种状态:
1.创建状态:创建新进程。
2.等待状态:进程能够运行,但没有得到许可,因为CPU分配给另一个进程。调度器可以在下一次任务切换时选择该进程。
3.运行状态:进程正在cpu中执行。
4.睡眠状态:进程正在睡眠无法运行,因为它在等待一个外部事件。
5.终止状态:进程消亡。

系统将所有进程保存在一个进程表中,无论其状态是运行、睡眠或等待。但睡眠进程会特别标记出来,调度器会知道它们无法立即运行。睡眠进程会分类到若干队列中,因此它们可在适当的时间唤醒,例如在进程等待的外部事件已经发生时。详细的进程状态间关系图如下所示:

在这里插入图片描述
Linux内核在include/linux/sched.h文件中也为进程定义了多种状态:

/* Used in tsk->state: */
#define TASK_RUNNING                    0x0000
#define TASK_INTERRUPTIBLE              0x0001
#define TASK_UNINTERRUPTIBLE            0x0002
#define __TASK_STOPPED                  0x0004
#define __TASK_TRACED                   0x0008
/* 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

其中比较常用的就是下面的5种:

  • TASK_RUNNING(可运行状态):对应上图的等待状态或者运行状态。它是指进程处于可运行的状态,或许正在运行,或许在就绪队列(本书中也称为调度队列)中等待运行。
  • TASK_INTERRUPTIBLE(可中断睡眠态):对应上图的睡眠状态。进程进入睡眠状态(被阻塞)来等待某些条件的达成或者某些资源的就位,一旦条件达成或者资源就位,内核就可以把进程的状态设置成TASK_RUNNING并将其加入就绪队列中。也有人将这个状态称为浅睡眠状态。
  • TASK_UNINTERRUPTIBLE(不可中断态):对应上图的睡眠状态。这个状态和上面的TASK_INTERRUPTIBLE状态类似,唯一不同的是,进程在睡眠等待时不受干扰,对信号不做任何反应,所以这个状态称为不可中断态。通常使用ps命令看到的被标记为D状态的进程,就是处于不可中断态的进程,不可以发送SIGKILL信号使它们终止,因为它们不响应信号。也有人把这个状态称为深度睡眠状态。
  • EXIT_ZOMBIE(僵尸态):对应上图的终止状态。进程已经消亡,但是task_struct数据结构还没有释放,这个状态叫作僵尸态。
  • __TASK_STOPPED(终止态):对应上图的终止状态。进程停止运行。task_struct中的资源包括task_struct数据已经释放完了。
    三、进程优先级
    并非所有进程都具有相同的重要性。除了大家熟悉的进程优先级之外,进程还有不同的关键度类别,以满足不同需求。首先要知道linux的进程分为以下几种,每一种的优先级都是不一样的:
    1.期限进程:优先级为-1。优先级最高。
    2.实时进程:优先级1-99,优先级数值越大便是优先级越高。
    3.普通进程:优先级为100-139,优先级数值越小便是优先级越高。可以通过nice值改变普通进程优先级。
    4.空闲进程:优先级为140。优先级最低。

四、进程表示
Linux内核涉及进程和程序的所有算法都围绕一个名为 task_struct 的数据结构建立,该结构定义在 include/linux/sched.h 中。这是系统中主要的一个结构。task_struct 包含很多成员,将进程与各个内核子系统联系起来,我们看看代码:


struct task_struct {
#ifdef CONFIG_THREAD_INFO_IN_TASK/** For reasons of header soup (see current_thread_info()), this* must be the first element of task_struct.*/struct thread_info		thread_info;//把thread_info从栈中抽出来,方便current宏的实现
#endif/* -1 unrunnable, 0 runnable, >0 stopped: */volatile long			state; //表示进程的状态标志/** This begins the randomizable portion of task_struct. Only* scheduling-critical items should be added above here.*/randomized_struct_fields_startvoid				*stack;//指向内核栈的指针refcount_t			usage;//进程描述符使用计数,被置为2时,表示进程描述符正在被使用而且其相应的进程处于活动状态/* Per task flags (PF_*), defined further below: */unsigned int			flags;//标记,表示进程的类型unsigned int			ptrace;#ifdef CONFIG_SMPstruct llist_node		wake_entry;int				on_cpu;
#ifdef CONFIG_THREAD_INFO_IN_TASK/* Current CPU: */unsigned int			cpu;//当前运行的cpuid
#endifunsigned int			wakee_flips;unsigned long			wakee_flip_decay_ts;struct task_struct		*last_wakee;/** recent_used_cpu is initially set as the last CPU used by a task* that wakes affine another task. Waker/wakee relationships can* push tasks around a CPU where each wakeup moves to the next one.* Tracking a recently used CPU allows a quick search for a recently* used CPU that may be idle.*/int				recent_used_cpu;//上一次调度时使用的cpuidint				wake_cpu;
#endifint				on_rq;int				prio;//进程的当前优先级。一般等于normal_prio,但是当进程A占有互斥锁并且进程B在等待锁的时候,会把A进程的优先级临时提高int				static_prio;//普通进程的静态优先级,就是120+nice,若是限期进程或者实时进程则为0int				normal_prio;//普通进程的正常优先级,一般等于static_prio,若是限期进程则为-1,若是实时进程,则为99-rt_priorityunsigned int			rt_priority;//实时进程的优先级,数值越大优先级越高,如果是限期进程或者普通进程,则为0const struct sched_class	*sched_class;//进程的调度类struct sched_entity		se;//普通进程的调度实体struct sched_rt_entity		rt;//实时进程的调度实体
#ifdef CONFIG_CGROUP_SCHEDstruct task_group		*sched_task_group;//指向进程所在的cgroup
#endifstruct sched_dl_entity		dl;//deadline进程的调度实体#ifdef CONFIG_UCLAMP_TASK/* Clamp values requested for a scheduling entity */struct uclamp_se		uclamp_req[UCLAMP_CNT];/* Effective clamp values used for a scheduling entity */struct uclamp_se		uclamp[UCLAMP_CNT];
#endif#ifdef CONFIG_PREEMPT_NOTIFIERS/* List of struct preempt_notifier: */struct hlist_head		preempt_notifiers;
#endif#ifdef CONFIG_BLK_DEV_IO_TRACEunsigned int			btrace_seq;
#endifunsigned int			policy;//进程调度策略int				nr_cpus_allowed;//该进程允许使用的cpu的数量const cpumask_t			*cpus_ptr;//表示该进程允许在哪个cpu上运行cpumask_t			cpus_mask;//表示该进程不允许在哪个cpu上运行...struct sched_info		sched_info;//记录进程运行时的实时信息struct list_head		tasks;//进程链表
#ifdef CONFIG_SMPstruct plist_node		pushable_tasks;struct rb_node			pushable_dl_tasks;
#endifstruct mm_struct		*mm;//指向内存描述符,如果是内核进程,则为空struct mm_struct		*active_mm;//指向内存描述符,如果是内核进程,则指向从进程借用的内存描述符/* Per-thread vma caching: */struct vmacache			vmacache;#ifdef SPLIT_RSS_COUNTINGstruct task_rss_stat		rss_stat;
#endifint				exit_state;//进程的退出状态,int				exit_code;//进程的终止代号int				exit_signal;//进程接受到的退出信号/* The signal sent when the parent dies: */int				pdeath_signal;//表示当父进程死亡时要发送的信号,然后托管给0进程/* JOBCTL_*, siglock protected: */unsigned long			jobctl;
...unsigned long			atomic_flags; /* Flags requiring atomic access. */struct restart_block		restart_block;pid_t				pid;//表示该进程的进程号pid_t				tgid;//表示该进程的线程号#ifdef CONFIG_STACKPROTECTOR/* Canary value for the -fstack-protector GCC feature: */unsigned long			stack_canary;
#endif/** Pointers to the (original) parent process, youngest child, younger sibling,* older sibling, respectively.  (p->father can be replaced with* p->real_parent->pid)*//* Real parent process: */struct task_struct __rcu	*real_parent;//指向创建进程的进程描述符(生父进程),如果生父进程不存在了,指向进程1(systemd进程)/* Recipient of SIGCHLD, wait4() reports: */struct task_struct __rcu	*parent;//指向进程的当前父进程,一般和real_parent一致,只有在调试的时候指向调试的进程/** Children/sibling form the list of natural children:*/struct list_head		children;//指向该进程的子进程链表struct list_head		sibling;//指向进程的兄弟进程struct task_struct		*group_leader;//一般是指向自己,如果该进程是用户创建的线程,则指向创建线程的进程.../* Process credentials: *//* Tracer's credentials at attach: */const struct cred __rcu		*ptracer_cred;/* Objective and real subjective task credentials (COW): */const struct cred __rcu		*real_cred;//指向客观和真实的主观任务凭证/* Effective (overridable) subjective task credentials (COW): */const struct cred __rcu		*cred;//指向有效的主观任务凭证#ifdef CONFIG_KEYS/* Cached requested key. */struct key			*cached_requested_key;
#endif/** executable name, excluding path.** - normally initialized setup_new_exec()* - access it with [gs]et_task_comm()* - lock it with task_lock()*/char				comm[TASK_COMM_LEN];//进程的名称struct nameidata		*nameidata;#ifdef CONFIG_SYSVIPCstruct sysv_sem			sysvsem;//用于信号量struct sysv_shm			sysvshm;//用于共享内存
#endif
#ifdef CONFIG_DETECT_HUNG_TASKunsigned long			last_switch_count;unsigned long			last_switch_time;
#endif/* Filesystem information: */struct fs_struct		*fs;//指向进程的当前工作目录/* Open file information: */struct files_struct		*files;//打开的文件/* Namespaces: */struct nsproxy			*nsproxy;//命名空间/* Signal handlers:主要用于信号处理 */struct signal_struct		*signal;//指向进程的信号描述符struct sighand_struct		*sighand;//指向进程的信号处理程序描述符sigset_t			blocked;//表示被阻塞信号的掩码sigset_t			real_blocked;//临时掩码/* Restored if set_restore_sigmask() was used: */sigset_t			saved_sigmask;//使用了set_restore_sigmask()则恢复的掩码struct sigpending		pending;//存放私有挂起信号的数据结构unsigned long			sas_ss_sp;//信号处理程序备用堆栈的地址size_t				sas_ss_size;//堆栈的大小unsigned int			sas_ss_flags;//堆栈的标志位struct callback_head		*task_works;
...
#ifdef CONFIG_LOCKDEP
# define MAX_LOCK_DEPTH			48ULu64				curr_chain_key;int				lockdep_depth;//表示获取大内核锁的次数unsigned int			lockdep_recursion;struct held_lock		held_locks[MAX_LOCK_DEPTH];
#endif
...
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/215726.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Shell循环:for(二)

一、通过用户列表文件创建用户 需求:通过用户列表文件创建用户 [rootlocalhost ~]# cat user.txt qian yoa huang演示: [rootlocalhost ~]# vim foruser.sh #编写脚本 #!/bin/bash for i in cat user.txt do useradd $i if [ $? -eq 0 ] thenech…

思科模拟器操作命令

模式 思科模拟器常见的模式有 用户模式 能够操作的命令比较少 特权模式特权模式下面可以操作的比较多 全局模式 接口模式 用户模式进入特权模式: 命令enable 特权模式进行全局模式命令: configure terminal 退出命令 exit命令:返回上一层,即一步一步…

canvas高级动画001:文字瀑布流

canvas实例应用100 专栏提供canvas的基础知识,高级动画,相关应用扩展等信息。 canvas作为html的一部分,是图像图标地图可视化的一个重要的基础,学好了canvas,在其他的一些应用上将会起到非常重要的帮助。 文章目录 示例…

拿捏---JVM原理

文章目录 JVM内存划分JVM类加载为什么需要类加载?类加载的过程何时触发类加载?双亲委派模型 JVM的垃圾回收机制(GC)什么是垃圾回收?GC回收哪部分内存?回收机制怎么找出垃圾?引用计数可达性分析&…

物流实时数仓:数仓搭建(ODS)

系列文章目录 物流实时数仓:采集通道搭建 物流实时数仓:数仓搭建 文章目录 系列文章目录前言一、IDEA环境准备1.pom.xml2.目录创建 二、代码编写1.log4j.properties2.CreateEnvUtil.java3.KafkaUtil.java4.OdsApp.java 三、代码测试总结 前言 现在我们…

大模型推理加速框架vllm部署的实战方案

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

堆的实现(堆的插入、堆的删除等)超级全

堆的实现(堆的插入、堆的删除等)超级全 文章目录 堆的实现(堆的插入、堆的删除等)超级全一、前期基础知识1.树结构①树的定义②树的相关概念③二叉树④满二叉树和完全二叉树a.满二叉树b.完全二叉树 ⑤二叉树的性质⑥二叉树顺序结构…

YOLOv8改进 | 2023 | LSKAttention大核注意力机制助力极限涨点

论文地址:官方论文地址 代码地址:官方代码地址 一、本文介绍 在这篇文章中,我们将讲解如何将LSKAttention大核注意力机制应用于YOLOv8,以实现显著的性能提升。首先,我们介绍LSKAttention机制的基本原理,…

深入理解 Django 中的事务管理

概要 在数据库操作中,事务是确保数据完整性和一致性的关键机制。Django 作为一个强大的 Python Web 框架,提供了灵活而强大的事务管理功能。理解和正确使用 Django 中的事务对于开发高质量的 Web 应用至关重要。本文将深入探讨 Django 的事务管理机制&a…

2021年12月 Scratch(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 执行下列程序,屏幕上可以看到几只小猫? A:1 B:3 C:4 D:0 答案:B 第2题 下列程序哪个可以实现:按下空格键,播放完音乐后说“你好!”2秒? A: B: C:

人工智能-注意力机制之注意力汇聚:Nadaraya-Watson 核回归

查询(自主提示)和键(非自主提示)之间的交互形成了注意力汇聚; 注意力汇聚有选择地聚合了值(感官输入)以生成最终的输出。 本节将介绍注意力汇聚的更多细节, 以便从宏观上了解注意力机…

SpringCloud实用-OpenFeign整合okHttp

文章目录 前言正文一、OkHttpFeignConfiguration 的启用1.1 分析配置类1.2 得出结论,需要增加配置1.3 调试 二、OkHttpFeignLoadBalancerConfiguration 的启用2.1 分析配置类2.2 得出结论2.3 测试 附录附1:本系列文章链接附2:OkHttpClient 增…