2. Linux进程管理

2. 进程管理

2.1 Linux进程

  • 进程是程序执行时的一个动态实体,包含程序计数器、全部CPU 寄存器的值和进程堆栈中存储着的一些临时数据,如子程序参数、返回地址及变量等,反映的是当前处理器的活动状态。 而程序是仅包含指令和数据的一段静态代码。
  • Linux 是一个多处理操作系统,进程拥有独立的权限和单一职责,每个进程都运行在各自独立的虚拟地址空间中,只有通过内核控制下的进程通信机制(管道、信号、信号量、消息队列等),它们之间才能发生通信。
  • 从内核的观点看, 进程的目的就是担当分配系统资源(CPU 时间、内存等)的实体。 进程管理的最终目的就是在各进程顺畅执行的条件下,合理分配系统资源给不同的进程。
  • 子进程刚被创建时,是父进程地址空间的一个(逻辑)备份,与父子进程共享程序代码,但它们分别拥有独立的数据备份。因此子进程对堆和栈中的数据进行修改时,对父进程的数据是不会有影响的。

2.2 进程描述符

  • 内核对进程的优先级、进程的状态、地址空间等采用进程描述符表示。在 Linux 内核中,进程用一个相当大的称为 task_struct 的结构表示。下面是从 linux-2.6.29\include\linux\sched.h 中摘抄出来的进程描述的部分信息:

    struct task_struct {volatile long state; 	/* 进程状态, -1:不能运行, 0:运行, >0:停止 */void *stack;atomic_t usage;unsigned int flags; 	/* 指示符,进程创建:PF_STARTING,退出:PF_EXITING,在分配内存:PF_MEMALLOC */unsigned int ptrace;int lock_depth; 		/* BKL lock depth *//* 每个进程都会被赋予优先级(称为 static_prio),但实际优先级是基于多因素动态决定的,值越低优先级越高。 */int prio, static_prio, normal_prio;unsigned int rt_priority;const struct sched_class *sched_class;struct sched_entity se;struct sched_rt_entity rt;unsigned char fpu_counter;s8 oomkilladj; 			/* OOM kill score adjustment (bit shift). */unsigned int policy;cpumask_t cpus_allowed;struct list_head tasks; /* 提供链接能力,包含prev指针指向前一个任务,next指针指向下一个任务 *//* 进程地址空间由mm和active_mm表示,mm代表进程内存描述符,active_mm代表前一进程内存描述符(为改进上下文切换时间的一种优化) */struct mm_struct *mm, *active_mm;/* task state */struct linux_binfmt *binfmt;int exit_state;int exit_code, exit_signal;int pdeath_signal; 		/* The signal sent when the parent dies */unsigned int personality;unsigned did_exec:1;pid_t pid;pid_t tgid;struct task_struct *real_parent; /* real parent process */struct task_struct *parent; 	/* recipient of SIGCHLD, wait4() reports */struct list_head children; 		/* list of my children */struct list_head sibling; 		/* linkage in my parent's children list */struct task_struct *group_leader; /* threadgroup leader */struct list_head ptraced;struct list_head ptrace_entry;struct pid_link pids[PIDTYPE_MAX];struct list_head thread_group;struct completion *vfork_done; 	/* for vfork() */int __user *set_child_tid; 		/* CLONE_CHILD_SETTID */int __user *clear_child_tid; 	/* CLONE_CHILD_CLEARTID */...
    };
    

2.3 进程状态

  • 进程描述符中 state 字段描述进程当前的状态。它由一组标志组成,其中每个标志描述一种可能的进程状态。在 2.6 内核中,进程只能处于这些状态中的一种。下面分别对这些状态进行描述。
    • 可运行状态TASK_RUNNING):进程处于运行(系统当前进程)或者准备运行状态(等待系统将 CPU 分配给它)。
    • 等待状态WAITING):进程在等待一个事件或者资源。 Linux 将等待进程分成两类:可中断的等待状态( TASK_TNTERRUPTIBLE)与不可中断的等待状态(TASK_UNINTERRUPTIBLE)。前者可被信号中断,后者直接在硬件条件等待,并且任何情况下都不可中断。
    • 暂停状态TASK_STOPPED) : 进程被暂停, 通常是通过接收一个信号(SIGSTOP、SIGTSTP、 SIGTTIN 或 SIGTTOU)转为暂停状态。正在被调试的进程可能处于停止状态。
    • 僵死状态EXIT_ZOMBIE) : 进程的执行被终止, 但其父进程还没有执行wait4() waitpid()系统调用返回有关该死亡进程的信息。

2.4 进程调度

  • Linux 进程调度指的是在所有可运行状态的进程中选择最值得运行的。每个进程的 task_struct 结构中的 policyprioritycounterrt_priority 这 4 项,是选择进程的依据。
    • policy :进程调度策略,用于区分普通进程和实时进程,实时进程优先于普通进程运行;
    • priority :进程(包括实时和普通)的静态优先级;
    • counter:进程剩余时间片,起始值就是 priority 的值;因为 counter 用于计算一个处于可运行状态的进程值得运行的程度( goodness),所以 counter 也被看做是进程的动态优先级。
    • rt_priority:实时进程特有的优先级别,用于实时进程间的选择。
  • Linux进程分类
    Linux 在执行进程调度的时候,对不同类型的进程采取的策略也不同,一般将 Linux
    分为以下 3 类:
    • 交互式进程:当有用户输入时,这类进程必须很快地激活。通常要求延迟在 50~150 毫秒。典型的交互式进程有控制台命令、文本编辑器、图形应用程序等。
    • 批处理进程(Batch Process):这类进程一般在后台运行,所以不需要非常快地反应,经常被调度期限制。典型的批处理进程有编译器、数据库搜索引擎和科学计算等。
    • 实时进程:这类进程对调度(时间)有非常严格的要求,不能被低优先级进程阻塞,在很短时间内需做出反应。典型的实时进程有音视频应用程序、机器人控制等。
  • Linux进程优先级
    Linux 系统中每一个普通进程都有一个静态优先级,它被调度器作为参考来调度进程。在内核中调度的优先级区间为**[100,139]**,数字越小,优先级越高。一个新的进程总是从它的父进程继承此值。此外, Linux 进程优先级还包括动态优先级、实时优先级等,各个进程优先级描述如下:
    • 静态优先级(priority):被称为“静态”是因为它不随时间而改变,只能由用户进行修改。它指明了在被迫和其他进程竞争 CPU 之前,该进程所被允许的时间片的最大值(20)。
    • 动态优先级(counter): counter 即系统为每个进程运行而分配的时间片。 Linux用它来表示进程的动态优先级。 当进程拥有 CPU 时, counter 就随着时间不断减小,当它递减为 0 时,标记该进程将重新调度。它指明了在当前时间片中所剩余的时间量(最初为 20)。
    • 实时优先级(rt_priority):它的变化范围是从 0~99。任何实时进程的优先级都高于普通的进程。
    • Base time quantum:是由静态优先级决定,当进程耗尽当前 Base time quantum,kernel 会重新分配一个 Base time quantum 给它。静态优先级和 Base time quantum的关系如下所述 :
      • 当静态优先级<120: Base time quantum(ms) = (140 – priority) * 20
      • 当静态优先级>= 120: Base time quantum(ms) = (140 – priority) * 5
  • Linux进程的调度算法
    • 时间片轮转调度算法(round-robin): SCHED_RR 用于实时进程。系统使每个进程依次地按时间片轮流执行的方式。
    • 优先权调度算法: SCHED_NORMAL 用于非实时进程。每次系统都会选择队列中优先级最高的进程运行。 Linux 采用抢占式的优级算法,即系统中当前运行的进程永远是可运行进程中优先权最高的进程。
    • 先进先出调度算法(FIFO): SCHED_FIFO 用于实时进程。采用 FIFO 调度算法选择的实时进程必须是运行时间较短的进程,因为这种进程一旦获得 CPU 就只有等到它运行完或因等待资源主动放弃 CPU 时,其他进程才能获得运行机会。

2.5 进程地址空间

  • Linux 的虚拟地址空间为 0~4GB,其分为内核空间和用户空间两部分。将最高的 1GB(从虚拟地址 0xC0000000~0xFFFFFFFF)留给内核使用,称为“内核空间”;较低的 3GB(从虚拟地址 0x00000000~0xBFFFFFFF)留给用户进程使用,称为“用户空间”。因为每个进程可以通过系统调用进入内核,因此, Linux 内核空间被系统的所有进程共享,实际上对于每个进程来说,它仍然可以拥有 4GB 的虚拟空间。

  • 虚拟地址空间并不是实际的地址空间,在为进程分配地址空间时,根据进程需要的空间进行分配, 4GB 仅仅是最大限额而已,并非一次性将 4GB 分配给进程。一般进程的地址空间总是小于 4GB 的,可以通过查看/proc/pid/maps 文件来获悉某个具体进程的地址空间。

  • 进程的地址空间并不对应实际的物理页, Linux 采用Lazy 的机制来分配实际的物理页(Demand paging 和“写时复制(Copy On Write)的技术”),从而提高实际内存的使用率。虚拟页和物理页
    的对应是通过映射机制来实现的,即通过页表进行映射到实际的物理页。因为每个进程都有自己的页表,因此可以保证不同进程的相同虚拟地址可以映射到不同的物理页,从而为不同的进程都可以同时拥有 4GB 的虚拟地址空间提供了可能。

  • 内核是系统中优先级最高的部分,所以内核函数申请动态内存时系统不会推迟这个请求;但用户进程申请内存空间时,进程的可执行文件被装入后,进程不会立即对所有的代码进行访问。因此内核总是尽量推迟给用户进程分配动态空间。内核分配空间时,通过__get_free_pages()alloc_pages 从分区页框分配器中获得页框; 通过 kmem_cache_alloc()kmalloc()函数使用 slab 分配器为对象分配块;通过 vmalloc() vmalloc32()函数获得一块非连续的内存区。

  • 与进程地址空间有关的全部信息都包含在内存描述符的数据结构 mm_structs中。 进程描述符的 mm字段就是指向这个结构。

  • 进程地址空间得创建与删除

    1. 内核调用copy_mm()函数建立新进程的所有页表和内存描述符,来创建进程的地址空间。

      static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
      {struct mm_struct * mm, *oldmm;int retval;tsk->min_flt = tsk->maj_flt = 0;tsk->nvcsw = tsk->nivcsw = 0;tsk->mm = NULL;tsk->active_mm = NULL;/*如果是内核线程的子线程则直接退出,即 mm 和 active_mm 均为 NULL*/oldmm = current->mm;if (!oldmm)return 0;/*内核线程,只是增加当前进程的虚拟空间的引用计数*/if (clone_flags & CLONE_VM) {/*如果共享内存,将 mm 由父进程赋值给子进程,两个进程将会指向同一块内存*/atomic_inc(&oldmm->mm_users);mm = oldmm;goto good_mm;}retval = -ENOMEM;mm = dup_mm(tsk); /*完成了对 vm_area_struct 和页面表的复制*/if (!mm)goto fail_nomem;
      good_mm:/* Initializing for Swap token stuff */mm->token_priority = 0;mm->last_interval = 0;/*内核线程的 mm 和 active_mm 指向当前进程的 mm_struct 结构*/tsk->mm = mm;tsk->active_mm = mm;return 0;fail_nomem:return retval;
      }
      
    2. 内核调用 exit_mm()函数释放进程的地址空间

      static void exit_mm(struct task_struct * tsk)
      {m_release(tsk, mm);/*得到读写信号量*/down_read(&mm->mmap_sem);core_state = mm->core_state;if (core_state) {struct core_thread self;/*释放读写信号量*/up_read(&mm->mmap_sem);self.task = tsk;self.next = xchg(&core_state->dumper.next, &self);if (atomic_dec_and_test(&core_state->nr_threads))complete(&core_state->startup);for (;;) {set_task_state(tsk, TASK_UNINTERRUPTIBLE);if (!self.task) /*take 字段可以查看函数 coredump_finish()*/break;schedule();}__set_task_state(tsk, TASK_RUNNING);down_read(&mm->mmap_sem);}atomic_inc(&mm->mm_count);BUG_ON(mm != tsk->active_mm);/* more a memory barrier than a real lock */task_lock(tsk);tsk->mm = NULL;up_read(&mm->mmap_sem);enter_lazy_tlb(mm, current);/*释放用户虚拟空间的数据结构*/clear_freeze_flag(tsk);task_unlock(tsk);mm_update_next_owner(mm);/*递减 mm 的引用计数并是否为 0,如是,则释放 mm 所代表的映射*/mmput(mm);
      }
      

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

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

相关文章

【Appium UI自动化】pytest运行常见错误解决办法

通过Appium工具录制代码在pycharm上运行报错&#xff1a; 错误一&#xff1a; 1.提示 setup() 方法运行 error failed 解决办法&#xff1a;未创建 init __ 方法&#xff0c;创建一个空的__init.py文件就解决了。 原因&#xff1a; 错误二&#xff1a; 2.运行代码&#xff…

Linux之ACL权限管理

文章目录 1.ACL权限介绍二、操作步骤1. 添加测试目录、用户、组&#xff0c;并将用户添加到组2. 修改目录的所有者和所属组3. 设定权限4. 为临时用户分配权限5. 验证acl权限6. 控制组的acl权限 1.ACL权限介绍 每个项目成员有一个自己的项目目录&#xff0c;对自己的目录有完全…

构建生物医学知识图谱from zero to hero (4):通过Neo4j构建知识图谱

图数据库是一种专门用于存储图形数据的 NoSQL 数据库。与传统的关系型数据库和其他 NoSQL 数据库不同,图数据库利用图形数据模型来存储和管理数据。图形数据模型由节点和边组成,节点代表实体,边代表实体之间的关系。例如,在社交网络中,用户可以表示为节点,朋友关系可以表…

xff注入 [CISCN2019 华东南赛区]Web111

打开题目 看见smarty 想到模板注入 又看见ip 想到xff注入 一般情况下输入{$smarty.version}就可以看到返回的smarty的版本号。该题目的Smarty版本是3.1.30 在Smarty3的官方手册里有以下描述: Smarty已经废弃{php}标签&#xff0c;强烈建议不要使用。在Smarty 3.1&#xff…

C# OpenVINO 百度PaddleSeg实时人像抠图PP-MattingV2

目录 效果 项目 代码 下载 C# OpenVINO 百度PaddleSeg实时人像抠图PP-MattingV2 效果 项目 代码 using OpenCvSharp; using Sdcb.OpenVINO; using System; using System.Diagnostics; using System.Drawing; using System.Security.Cryptography; using System.Text; us…

SparkSQL学习03-数据读取与存储

文章目录 1 数据的加载1.1 方式一&#xff1a;spark.read.format1.1.1读取json数据1.1.2 读取jdbc数据 1.2 方式二&#xff1a;spark.read.xxx1.2.1 读取json数据1.2.2 读取csv数据1.2.3 读取txt数据1.2.4 读取parquet数据1.2.5 读取orc数据1.2.6 读取jdbc数据 2 数据的保存2.1…

SmartX 携手 openGauss 社区发布联合方案评测与性能最佳实践

近日&#xff0c;北京志凌海纳科技有限公司&#xff08;以下简称 “SmartX”&#xff09;携手 openGauss 社区完成了 openGauss 数据库基于 SmartX 超融合平台&#xff08;SMTX OS&#xff09;和 SmartX 分布式存储平台&#xff08;SMTX ZBS&#xff09;的性能测试和调优。 结果…

JavaScript中的可选链——通过示例解释

JavaScript开发经常涉及导航嵌套对象&#xff0c;这可能很麻烦且容易出错&#xff0c;特别是在处理null或undefined值时。可选链是现代JavaScript语法中的一个改革性特性。 在本文中&#xff0c;我们将通过实际示例探讨可选链&#xff0c;演示它如何简化代码并使开发更加高效。…

MySQL数据库基础(十三):关系型数据库三范式介绍

文章目录 关系型数据库三范式介绍 一、什么是三范式 二、数据冗余 三、范式的划分 四、一范式 五、二范式 六、三范式 七、总结 关系型数据库三范式介绍 一、什么是三范式 设计关系数据库时&#xff0c;遵从不同的规范要求&#xff0c;设计出合理的关系型数据库&…

代码随想录算法训练营第五十九天|

583. 两个字符串的删除操作 本题和动态规划&#xff1a;115.不同的子序列 相比&#xff0c;其实就是两个字符串都可以删除了&#xff0c;情况虽说复杂一些&#xff0c;但整体思路是不变的。 代码随想录 class Solution {public int minDistance(String word1, String word2) {…

流畅的Python(十一)-从协议到抽象基类

一、核心要义 主要讨论Python中的接口&#xff0c;所谓接口就是类实现或继承的一套公开(按照定义,受保护的属性和私有属性不在接口中)属性和方法&#xff0c;包括特殊方法&#xff0c;如__getitem__或__add__等。Python有两套规范接口的方式: 1. 鸭子类型和协议&#xff0c;这…

几种后端开发中常用的语言。

几种后端开发中常用的语言。 C/C 语言 C 语言最初是用于系统开发工作&#xff0c;特别是组成操作系统的程序。由于 C 语言所产生的代码运行速度与汇编语言编写的代码运行速度几乎一样&#xff0c;所以采用 C 语言作为系统开发语言。目前&#xff0c;C 语言是最广泛使用的系统…

MongoDB聚合运算符:$atan2

$atan2用来计算反正切&#xff0c;返回指定表达式的反正切值&#xff0c;与$antan的区别主要是参数不同。 语法 { $atan2: [<expression1>, <expression1>] }<expression>为可被解析为数值的表达式$atan2返回弧度&#xff0c;使用$radiansToDegrees运算符可…

数据结构与算法-常用排序算法

一、常用排序说明 当涉及排序算法时&#xff0c;理解每个算法的工作原理、时间复杂度和空间复杂度是至关重要的。下面对常用排序算法进行详细说明&#xff1a; 1、冒泡排序&#xff08;Bubble Sort&#xff09;&#xff1a; 工作原理&#xff1a;比较相邻的元素并交换&am…

python bug与debug

一、什么是bug&#xff08;软件缺陷&#xff09;&#xff1f; 产品说明书中规定要做的事情&#xff0c;而软件没有实现。 产品说明书中规定不要做的事情&#xff0c;而软件确实现了。 产品说明书中没有提到过的事情&#xff0c;而软件确实现了。 产品说明书中没有提到但是必…

跨语言的序列化与反序列化

在Java中实现跨语言的序列化与反序列化通常可以采用以下几种方式 使用标准的跨语言序列化格式 可以选择使用一些标准的跨语言序列化格式,例如JSON、XML、Protocol Buffers(ProtoBuf)等。这些格式都是跨语言的,可以方便地在不同的编程语言之间进行数据交换。在Java中,可以…

紫光同创初使用

芯片PGC2KG-6LPG144 1、安装好软件接&#xff0c;加载license,有两个&#xff0c;与电脑MAC地址绑定的 2、正常使用后&#xff0c;新建个工程&#xff0c;配置管脚Tools→UCE 3、程序中有些信号被软件认为是时钟信号&#xff0c;会报错&#xff08;时钟输入I0约束在非专用时钟…

LeetCode--代码详解 78.子集

78.子集 题目 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[],[1…

Python爬虫-使用代理伪装IP

爬虫系列&#xff1a;http://t.csdnimg.cn/WfCSx 前言 我们在做爬虫的过程中经常会遇到这样的情况&#xff0c;最初爬虫正常运行&#xff0c;正常抓取数据&#xff0c;一切看起来都是那么的美好&#xff0c;然而一杯茶的功夫可能就会出现错误&#xff0c;比如 403 Forbidden&…

【LeetCode刷题笔记】242.有效的字母异位词

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 更多算法知识专栏&#xff1a;算法分析&#x1f525; 给大家跳段街舞感谢…